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:

  1. Identify (0x20) — Initiates communication
  2. Negotiate (0x60+n) — Agrees on packet size, packet count, and baud rates
  3. Logon (0x50) — Authenticates with user ID and name
  4. Security (0x51) — Provides password (up to 20 bytes)
  5. ... perform table reads/writes and procedures ...
  6. Logoff (0x52) — Ends the authenticated session
  7. 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
Was this page helpful?