This library implements the main application-layer packet model used by the project.
Default bare packet format:
DeviceAddress(4) + FunctionCode(1) + FunctionData(N) + CRC16(2)
Optional envelope format:
C6 F4 C2 CC + Length(2) + BarePacket + 0D 0A
If your workflow is simply “send one frame, receive one frame”, the bare packet APIs are the primary path.
Recommended order from highest level to lowest level:
QlKnownOperationsQlProtocolKnownRouterQlProtocolKnownCommands/QlProtocolKnownParsersQlProtocolCommandBuilder/QlProtocolParser/QlProtocolFrameExtensionsQlPayloadCodec
This protocol must not be treated as “one global byte-order rule for everything”.
Recommended interpretation:
- protocol control fields such as register addresses, register counts, and length fields use high-byte-first order
- payload value fields
such as
WORD,FLOAT, log content, and operation parameters must follow the specific function-code section and type definition
Current helper split:
EncodeUInt16 / DecodeUInt16for protocol control fieldsEncodeValueUInt16 / DecodeValueUInt16for 16-bit payload valuesEncodeUInt32 / DecodeUInt32for 32-bit payload valuesEncodeSingle / DecodeSinglefor floating-point payload values
Purpose: combine register metadata, read-command building, and typed response parsing.
Common members:
QlKnownOperations.DeviceTimeQlKnownOperations.RunStatusQlKnownOperations.DeviceNoQlKnownOperations.MeasureResultQlKnownOperations.VersionBundle
Common methods:
BuildRead(uint deviceAddress)BuildReadHex(uint deviceAddress)TryParse(QlProtocolFrame frame, out T value)Parse(QlProtocolFrame frame)
Purpose: route a known business frame to the correct typed result.
Common method:
TryParse(QlProtocolFrame frame, out QlKnownParseResult? result)
Purpose: build commands by business intent without exposing register addresses.
Typical methods:
BuildReadDeviceTime(uint deviceAddress)BuildReadRunStatus(uint deviceAddress)BuildReadDeviceNo(uint deviceAddress)BuildReadMeasureResult(uint deviceAddress)BuildReadVersionBundle(uint deviceAddress)BuildSetDeviceTime(uint deviceAddress, DateTime value)BuildWriteDeviceNo(uint deviceAddress, string deviceNo, int fixedByteLength = 16)BuildWriteAnalyzerCode(uint deviceAddress, string analyzerCode, int fixedByteLength = 16)
Purpose: parse responses for known business registers.
Typical methods:
TryParseDeviceTimeTryParseRunStatusTryParseDeviceNoTryParseAnalyzerCodeTryParseConcentrationTryParseMeasureResultTryParseKbInfoTryParseMeterStrongLightTryParseVersionBundle
Purpose: build frames directly from device address, function code, and function data.
Common methods:
BuildPacket(uint deviceAddress, byte rawFunctionCode, byte[] functionData, bool includeEnvelope = false)BuildRead(uint deviceAddress, ushort address, ushort registerCount, bool includeEnvelope = false)BuildRead(uint deviceAddress, QlRegisterDefinition register, bool includeEnvelope = false)BuildWrite(uint deviceAddress, ushort address, ushort registerCount, byte[] payload, bool includeEnvelope = false)BuildWrite(uint deviceAddress, QlRegisterDefinition register, byte[] payload, bool includeEnvelope = false)BuildWriteRegisters(uint deviceAddress, ushort address, params ushort[] registers)BuildWriteFloat(uint deviceAddress, ushort address, params float[] values)BuildWriteUtf8(uint deviceAddress, ushort address, string value, int fixedByteLength = 0)BuildSetTime(uint deviceAddress, DateTime value)BuildForward(uint deviceAddress, byte portId, byte[] forwardedContent, bool includeEnvelope = false)BuildForwardHex(uint deviceAddress, byte portId, byte[] forwardedContent, bool includeEnvelope = false)
Example:
uint deviceAddress = 0x10000001;
byte[] cmd = QlProtocolCommandBuilder.BuildRead(deviceAddress, 0x0000, 0x0001);
Console.WriteLine(QlHexConverter.ToHexString(cmd));
// 10 00 00 01 03 00 00 00 01 43 210x32 forwarding example:
byte[] forwardedContent = QlHexConverter.FromHexString(
"10 00 00 01 06 00 16 00 01 04 01 00 00 00 2E F9");
byte[] cmd = QlProtocolCommandBuilder.BuildForward(
0x1000000F,
0x01,
forwardedContent);
Console.WriteLine(QlHexConverter.ToHexString(cmd));
// 10 00 00 0F 32 00 11 01 10 00 00 01 06 00 16 00 01 04 01 00 00 00 2E F9 CE D2Purpose: parse a full frame into QlProtocolFrame.
Common methods:
Parse(byte[] frameBytes)ParseHex(string hex)TryParse(byte[] frameBytes, out QlProtocolFrame? frame)TryParseHex(string hex, out QlProtocolFrame? frame)
Notes:
- supports bare frames
- supports optionally wrapped frames
Purpose: carry parsed frame results.
Common properties:
RawBytesHasEnvelopeDeviceAddressDeviceAddressHexRawFunctionCodeFunctionCodeKindAddressRegisterCountPayloadByteCountDataLengthResponseCodeErrorCodeCrcComputedCrcIsCrcValid
Purpose: read typed values from parsed payload bytes.
Common methods:
ReadUInt16()ReadUInt32()ReadSingle()ReadSingles()ReadUtf8()ReadAscii()ReadBcdDateTime()ReadBcdDateTimeText()ReadUInt16Array()ReadForwardPortId()ReadForwardContent()Decode(QlRegisterDefinition register)TryDecodeKnownRegister(out QlDecodedRegisterValue? decoded)
0x32 parse example:
QlProtocolFrame frame = QlProtocolParser.ParseHex(
"10 00 00 0F 32 00 11 01 10 00 00 01 06 00 16 00 01 04 01 00 00 00 2E F9 CE D2");
byte portId = frame.ReadForwardPortId();
byte[] content = frame.ReadForwardContent();
Console.WriteLine(portId); // 1
Console.WriteLine(QlHexConverter.ToHexString(content));Purpose: low-level field and payload-value encoding/decoding helpers.
Common methods:
EncodeUInt16 / DecodeUInt16EncodeValueUInt16 / DecodeValueUInt16EncodeUInt32 / DecodeUInt32EncodeSingle / DecodeSingle / DecodeSinglesEncodeUtf8 / DecodeUtf8EncodeBcdDateTime / DecodeBcdDateTime / DecodeBcdDateTimeText
Current support:
- request building
- request parsing
- response parsing
- high-level known-register read support
Current support:
- request building
- request parsing
- simple response parsing
Current support:
- dedicated request helper:
BuildForward(...) - dedicated hex helper:
BuildForwardHex(...) - generic structural parsing
- dedicated parse helpers:
ReadForwardPortId()/ReadForwardContent()
Structure:
DeviceAddress(4) + 0x32(1) + DataLength(2) + PortId(1) + ForwardedContent(N) + CRC16(2)
Notes:
DataLength = PortId + ForwardedContentForwardedContentis usually another complete normal QL command
Current support:
- generic structural parsing
Notes:
- these function codes have richer business payload definitions
- the library currently focuses on structural support first
- deeper business interpretation can be added on top as needed
QlRunStatusInfoQlMeasureResultInfoQlKbInfoQlMeterStrongLightInfoQlVersionBundleInfoQlDecodedRegisterValueQlKnownParseResult
Known register definitions are provided in QlKnownRegisters:
DeviceNoMeasureResultRunStatusSubStatusRunModeMeasureModeWarnCodeFaultCodeDeviceTimeConcentrationWorkStateFlagKbInfoMeterStrongLightAnalyzerCodeVersionBundle
For business callers:
- prefer
QlKnownOperations - or
QlProtocolKnownCommands + QlProtocolKnownParsers
For protocol extension work:
- prefer
QlProtocolCommandBuilder - then combine it with
QlProtocolParser + QlProtocolFrameExtensions
For simple “send one frame, receive one frame” flows:
Build...+Parse...is usually enough
Purpose: decode only the optional wrapped stream format.
Important:
- it handles
C6 F4 C2 CC + Length + BarePacket + 0D 0A - bare packets themselves do not carry their own stream boundary marker
- for bare packets, the transport layer must preserve packet boundaries or you must manage framing externally