PSEM Protocol
SharpMeter implements the ANSI C12.18 (transport) and C12.19 (data model) Protocol Specification for Electric Metering (PSEM).
Session Lifecycle
A PSEM session follows a strict handshake sequence:
- Identify (0x20) — Initiates communication
- Negotiate (0x60+n) — Agrees on packet size, packet count, and baud rates
- Logon (0x50) — Authenticates with user ID and name
- Security (0x51) — Provides password (up to 20 bytes)
- ... perform table reads/writes and procedures ...
- Logoff (0x52) — Ends the authenticated session
- Terminate (0x21) — Closes the connection
PsemClient.ConnectAsync() handles steps 1-4 automatically. DisconnectAsync() handles 6-7.
Reading Tables
Tables are the fundamental data unit in C12.19. Standard Tables (ST) range 0-2047, Manufacturing Tables (MT) 2048-4095.
Full Table Read
var result = await client.ReadTableAsync(tableId: 1); // ST1: General MFG ID
if (result.IsSuccess)
{
var data = result.Value;
Console.WriteLine($"{data.DisplayName}: {data.Length} bytes");
// data.Data contains the raw bytes
}
Partial (Offset) Read
var result = await client.ReadTableOffsetAsync(
tableId: 1,
offset: 0,
count: 4); // Read first 4 bytes (manufacturer code)
Streaming Large Tables
For tables larger than the packet size, use IAsyncEnumerable streaming:
await foreach (var chunk in client.StreamTableAsync(
tableId: 64,
chunkSize: 64,
totalSize: 1024))
{
if (chunk.IsSuccess)
Console.WriteLine($"Chunk: {chunk.Value.Length} bytes");
else
Console.WriteLine($"Error: {chunk.Error}");
}
Writing Tables
byte[] data = [0x01, 0x02, 0x03];
var result = await client.WriteTableAsync(tableId: 100, data);
With offset:
var result = await client.WriteTableOffsetAsync(
tableId: 100,
offset: 4,
data: new byte[] { 0xAA, 0xBB });
Procedure Execution
Procedures are executed by writing to ST7 and reading the response from ST8.
Standard Procedures (SP)
var result = await client.ExecuteStandardProcedureAsync(
procedureId: 0, // SP 0: Cold Start
parameters: ReadOnlyMemory<byte>.Empty);
if (result.IsSuccess && result.Value == ProcedureResult.Completed)
Console.WriteLine("Procedure completed");
Manufacturer Procedures (MP)
byte[] parameters = [0x01, 0x00];
var result = await client.ExecuteManufacturerProcedureAsync(
procedureId: 67, // MP 67: Change meter mode
parameters: parameters);
Keep-Alive
Prevent session timeout during long operations:
await client.WaitAsync(); // Sends Wait (0x70) request
L2 Framing
SharpMeter handles PSEM L2 framing automatically:
- STP (0xEE) start-of-packet detection
- CRC-16 CCITT (reversed polynomial) verification
- ACK/NAK control byte handling
- Multi-packet assembly and sequencing
- Toggle bit tracking for frame ordering
The PsemFrame readonly record struct represents a decoded frame and can encode/decode to raw bytes.
Last updated: 2026-04-08