--- source_files: - DataPRO/RibeyeCommands/CommandBase.cs - DataPRO/RibeyeCommands/CalibrationCommands.cs - DataPRO/RibeyeCommands/InformationCommands.cs - DataPRO/RibeyeCommands/CommandPacket.cs - DataPRO/RibeyeCommands/ArmCommands.cs generated_at: "2026-04-16T03:49:10.362478+00:00" model: "Qwen/Qwen3-Coder-Next-FP8" schema_version: 1 sha256: "fc23195a4e943669" --- # Ribeye Command Library Documentation ## 1. Purpose This module provides a structured command abstraction layer for interacting with the **Ribeye** data acquisition system hardware. It implements concrete command classes for diagnostics, information retrieval, and arm/trigger control, built atop a common base (`CommandBase`) that handles low-level packet serialization, deserialization, and communication via the `ICommunication` interface. The library enables developers to issue structured commands (e.g., query serial number, arm device, retrieve current positions) and retrieve structured results, abstracting away the underlying ASCII-based protocol with `#`-delimited parameters and checksums. ## 2. Public Interface ### `CommandBase` (abstract class) - **Namespace**: `DTS.DASLib.Command.Ribeye` - **Inherits**: `AbstractCommandBase` - **Purpose**: Base class for all Ribeye commands; manages `CommandPacket` for command/response and provides string conversion utilities. #### Constructors - `CommandBase(ICommunication sock)` Initializes a new command instance with default timeout, creates a new `CommandPacket` for `command`. - `CommandBase(ICommunication sock, int TimeoutMillisec)` Initializes with explicit timeout, creates a new `CommandPacket` for `command`. #### Overridden Methods - `void CommandToString(ref List> lines)` Appends the ASCII representation of `command.OriginalBytes` (excluding `\r`/`\n`) to `lines`. - `void ResponseToString(ref List> lines)` Appends up to the first 30 ASCII characters of `response.OriginalBytes` (excluding `\r`/`\n`) to `lines`, or `"Empty response!"` if null. - `CommandPacketBase GetCommandPacket()` Returns a new empty `CommandPacket`. - `CommandPacketBase GetCommandPacket(byte[] buffer)` Returns a new `CommandPacket` initialized from `buffer`. --- ### `DiagnosticsCommands` (abstract class) - **Namespace**: `DTS.DASLib.Command.Ribeye` - **Inherits**: `CommandBase` - **Purpose**: Base class for diagnostics commands; sets `command.Type = CommandType.Diagnostics`. #### Constructors - `DiagnosticsCommands(ICommunication sock)` - `DiagnosticsCommands(ICommunication sock, int TimeoutMillisec)` Both set `command.Type = CommandType.Diagnostics` and call `command.SetCommand((byte)_Command, _Command.ToString())`. #### Protected Members - `abstract Commands _Command { get; }` Must be implemented by derived classes to specify the command byte and name. --- ### `QueryCurrentPositions` (concrete class) - **Inherits**: `DiagnosticsCommands` - **Purpose**: Queries current deflection positions (in mV) for all stack channels. #### Constructors - `QueryCurrentPositions(ICommunication sock)` - `QueryCurrentPositions(ICommunication sock, int TimeoutMillisec)` Initializes `command.Parameter[0] = "CURRENT_POSITIONS"`. #### Properties - `int NumberOfChannels { get; }` Number of stack channels returned in `Positions`. - `float[] Positions { get; }` Array of deflection values (mV) per channel. #### Overridden Methods - `CommandReceiveAction WholePackage()` Parses response: - `response.GetParameter(1, out int NumberOfPositions)` → sets `_numChannels`. - `response.GetParameter(2, out string PositionString)` → splits by `,`, then handles firmware quirk where last element contains space-separated values. - Parses each element as `float` into `_Positions`. --- ### `InformationCommands` (abstract class) - **Namespace**: `DTS.DASLib.Command.Ribeye` - **Inherits**: `CommandBase` - **Purpose**: Base class for information queries; sets `command.Type = CommandType.Information`. #### Constructors - `InformationCommands(ICommunication sock)` - `InformationCommands(ICommunication sock, int TimeoutMillisec)` Both set `command.Type = CommandType.Information` and call `command.SetCommand((byte)_Command, _Command.ToString())`. #### Protected Members - `abstract Commands _Command { get; }` Must be implemented by derived classes. --- ### `QuerySerialNumber` (concrete class) - **Inherits**: `InformationCommands` - **Purpose**: Queries device serial number. #### Constructors - `QuerySerialNumber(ICommunication sock)` - `QuerySerialNumber(ICommunication sock, int TimeoutMillisec)` Sets `command.Parameter[0] = "SERIAL_NUMBER"`. #### Properties - `string SerialNumber { get; }` Serial number string from `response.Parameter[1]`. #### Overridden Methods - `CommandReceiveAction WholePackage()` On success, extracts serial number via `response.GetParameter(1, out _serialnumber)`; silently ignores exceptions. --- ### `QueryNumberOfLEDs` (concrete class) - **Inherits**: `InformationCommands` - **Purpose**: Queries number of LEDs on device. #### Constructors - `QueryNumberOfLEDs(ICommunication sock)` - `QueryNumberOfLEDs(ICommunication sock, int TimeoutMillisec)` Sets `command.Parameter[0] = "HOW_MANY_LEDS"`. #### Properties - `uint NumberOfLEDs { get; }` LED count from `response.Parameter[1]`. #### Overridden Methods - `CommandReceiveAction WholePackage()` On success, extracts LED count via `response.GetParameter(1, out _numberOfLEDs)`. - `void ResponseToString(ref List> lines)` Appends `"NumberOfLEDs: {value}"` to `lines`. --- ### `QueryDataAvailable` (concrete class) - **Inherits**: `InformationCommands` - **Purpose**: Queries data collection timing parameters (note: uses `Commands.QueryNumberOfLEDs` command enum, but `"DUMPINFO"` parameter). #### Constructors - `QueryDataAvailable(ICommunication sock)` - `QueryDataAvailable(ICommunication sock, int TimeoutMillisec)` Sets `command.Parameter[0] = "DUMPINFO"`. #### Properties - `float TotalMS { get; }` Sum of `PreTriggerMS` and `PostTriggerMS`. - `float PreTriggerMS { get; }` Absolute value of negative pre-trigger time (ms). - `float PostTriggerMS { get; }` Post-trigger time (ms). #### Overridden Methods - `CommandReceiveAction WholePackage()` On success: - `response.GetParameter(1, out int NegativePreTriggerMS)` → `_preTriggerMS = Math.Abs(NegativePreTriggerMS)` - `response.GetParameter(2, out _postTriggerMS)` - `_totalMS = _preTriggerMS + _postTriggerMS` --- ### `ArmCommands` (abstract class) - **Namespace**: `DTS.DASLib.Command.Ribeye` - **Inherits**: `CommandBase` - **Purpose**: Base class for arm/trigger commands; sets `command.Type = CommandType.Arm`. #### Constructors - `ArmCommands(ICommunication sock)` - `ArmCommands(ICommunication sock, int TimeoutMillisec)` Both set `command.Type = CommandType.Arm` and call `command.SetCommand((byte)_Command, _Command.ToString())`. #### Protected Members - `abstract Commands _Command { get; }` --- ### `Arm` (concrete class) - **Inherits**: `ArmCommands` - **Purpose**: Arms the device for data collection. #### Constructors - `Arm(ICommunication sock)` - `Arm(ICommunication sock, int TimeoutMillisec)` Sets `command.Parameter[0] = "ARM"`. #### Properties (setters) - `uint TStopMS { set; }` Sets `command.Parameter[1]`. - `uint TPostMS { set; }` Sets `command.Parameter[2]`. --- ### `QueryArmAndTriggerStatus` (concrete class) - **Inherits**: `ArmCommands` - **Purpose**: Queries current arm/trigger status. #### Constructors - `QueryArmAndTriggerStatus(ICommunication sock)` - `QueryArmAndTriggerStatus(ICommunication sock, int TimeoutMillisec)` Sets `command.Parameter[0] = "S"`. #### Properties - `bool IsArmed { get; set; }` - `bool IsRecording { get; set; }` - `bool IsTriggered { get; set; }` #### Overridden Methods - `CommandReceiveAction WholePackage()` Parses `response.Parameter[1]` as `int StatusCode`. Maps via `StatusCodeEnum`: - `Idle` → all `false` - `Armed` → `IsArmed = IsRecording = true` - `Busy` → all `true` - `DataAvailable`/default → all `false` --- ### `Disarm` (concrete class) - **Inherits**: `ArmCommands` - **Purpose**: Disarms the device. #### Constructors - `Disarm(ICommunication sock)` - `Disarm(ICommunication sock, int TimeoutMillisec)` Sets `command.Parameter[0] = "D"`. --- ### `PrepareForDataCollection` (concrete class) - **Inherits**: `ArmCommands` - **Purpose**: Prepares device for data collection (e.g., erases buffer). #### Constructors - `PrepareForDataCollection(ICommunication sock)` - `PrepareForDataCollection(ICommunication sock, int TimeoutMillisec)` Sets `command.Parameter[0] = "ERASE"`. --- ### `DownloadTestData` (concrete class) - **Inherits**: `ArmCommands` - **Purpose**: Downloads test data (note: uses `Commands.QueryArmAndTriggerStatus` enum, but `"DUMPBIN"` parameter). #### Constructors - `DownloadTestData(ICommunication sock)` - `DownloadTestData(ICommunication sock, int TimeoutMillisec)` Sets `command.Parameter[0] = "DUMPBIN"`. #### Properties - `ushort[] Data { get; }` Raw unsigned 16-bit sample data. - `int StartTimeMS { set; }` Sets `command.Parameter[1]`. - `int StopTimeMS { set; }` Sets `command.Parameter[2]`. - `uint NumberOfChannels { get; }` Extracted from `response.Parameter[1]`. - `int ExpectedNumberOfSamples { get; }` Extracted from `response.Parameter[2]`. #### Methods - `void GetChannelData(int channel, out short[] signedADC)` Converts `ushort[] _Data` to signed `short[]` per channel (interleaved → deinterleaved). Throws if `channel` out of range. #### Overridden Methods - `CommandReceiveAction WholePackage()` Parses `response.Parameter[1]` (channels), `[2]` (samples), then converts `DownloadPacket.Data` to `_Data` (16-bit unsigned, little-endian with per-sample checksum byte). - `CommandReceiveAction ReceiveBlockOK(ICommunicationReport report)` Custom handling for `DownloadPacket` verification and parsing. - `CommandReceiveAction WholePackagePost()` Builds `QueryEventDataReport` with `short[][]` data. --- ### `Trigger` (concrete class) - **Inherits**: `ArmCommands` - **Purpose**: Manually triggers data acquisition. #### Constructors - `Trigger(ICommunication sock)` - `Trigger(ICommunication sock, int TimeoutMillisec)` Sets `command.Parameter[0] = "T"`. --- ### `CommandPacket` (concrete class) - **Namespace**: `DTS.DASLib.Command.Ribeye` - **Inherits**: `CommandPacketBase` - **Purpose**: Represents a command/response packet in the Ribeye protocol. #### Nested Types - `enum CommandType { Reserved, Arm, Attribute, Diagnostics, EventData, FirmwareUpdate, Information, QAandUtility, Realtime }` - `enum PacketState { Unknown, TooShort, OK }` #### Fields - `string[] Parameter` Array of `#`-delimited parameters. - `byte Checksum` Computed checksum over parameters. #### Constructors - `CommandPacket()` Initializes `Parameter = new string[0]`, `ShouldLog = true`. - `CommandPacket(byte[] Bytes)` Parses ASCII packet: splits on `#`, ignores `\r`/`\n`. #### Methods - `PacketState VerifyPacket(byte[] Bytes)` Returns `PacketState.OK` if `Bytes.Length >= 4`, ends with `\r\n`, and not error indicator (`?`). Returns `TooShort` if length < 4 or missing `\r\n`. - `byte[] ToBytes()` Serializes to ASCII: `param1#param2#...#checksum\r\n`. - `void ComputeCRCs()` Calls `ComputeChecksum()` (sum of all parameter bytes + `#`). - `void GetParameter(int Position, out T Value)` Parses `Parameter[Position]` as `T` (supports `double`, `float`, `int`, `string`, etc.). - `void SetParameter(int Position, T Value)` Sets `Parameter[Position] = value.ToString()`. #### Static Members - `void GetNextSequenceNumber()` Thread-safe increment of global sequence number. --- ### `DownloadPacket` (concrete class) - **Inherits**: `CommandPacket` - **Purpose**: Specialized packet for binary data downloads. #### Fields - `byte[] Data` Binary payload after header. #### Constructors - `DownloadPacket(byte[] Bytes)` Parses header (up to `\r`), then copies remaining bytes to `Data`. #### Static Methods - `PacketState VerifyPacket(byte[] Bytes, ref uint BytesExpected)` - If `BytesExpected == 0`: parses header (3 params), computes expected length: `BytesExpected = (numChannels * 2 + 1) * numSamples + headerLength`. - Returns `OK` if `Bytes.Length >= BytesExpected`, else `TooShort`. --- ## 3. Invariants - **Packet Protocol**: All commands/responses use ASCII with `#` as parameter delimiter, terminated by `\r\n`. Checksum is computed over parameters only (sum of bytes). - **Parameter Indexing**: `GetParameter`/`SetParameter` use 0-based indexing. Index `0` is always the command name (e.g., `"ARM"`, `"SERIAL_NUMBER"`). - **Command Type**: Each command class sets `command.Type` to its category (`Diagnostics`, `Information`, `Arm`, etc.) in the constructor. - **Response Parsing**: `WholePackage()` is only invoked after `response` is fully populated (via `VerifyPacket` and `DownloadPacket`/`CommandPacket` construction). - **Checksum Verification**: `CommandPacket.VerifyPacket` does **not** validate checksum correctness—only checks for presence of `\r\n` terminator. Checksum is computed but not validated in `VerifyPacket`. - **Thread Safety**: `GetNextSequenceNumber` uses a lock on `GlobalSequenceNumberLock`. - **Data Conversion**: `DownloadTestData` interprets binary data as little-endian 16-bit samples with interleaved checksum bytes (per sample), but conversion logic appears flawed (`i / _NumberOfChannels` offset is suspicious). --- ## 4. Dependencies ### External Dependencies (from imports) - `DTS.Common.ICommunication.ICommunication` Interface for network/socket communication. - `DTS.Common.Enums.DASFactory.DFConstantsAndEnums.CommandStatus` Used for `response.Status` and `StatusNoError`. - `DTS.Common.DASResource.Strings` Used for localized error strings (e.g., `QueryEventData_GetChannelData_Err1`). - `DTS.Common.Utilities.Logging.APILogger` Used for logging failures in `WholePackagePost`. - `DTS.DASLib.Command.CommandPacketBase` Base class for `CommandPacket` (not shown, but assumed to define `SequenceNumber`, `Status`, `OriginalBytes`, etc.). ### Inherited Dependencies - `AbstractCommandBase` (from `DTS.DASLib.Command`) Provides core command execution logic, timeout handling, and `baseCommand`/`baseResponse`. ### Inherited By - All Ribeye command classes (`QueryCurrentPositions`, `QuerySerialNumber`, `Arm`, etc.) depend on `CommandBase`. - `DownloadTestData` depends on `DownloadPacket` for binary data handling. --- ## 5. Gotchas - **Incorrect Command Enum Usage**: - `QueryDataAvailable` sets `_Command = Commands.QueryNumberOfLEDs` (0x01) but uses `"DUMPINFO"` parameter. - `DownloadTestData` sets `_Command = Commands.QueryArmAndTriggerStatus` (0x03) but uses `"DUMPBIN"` parameter. This suggests historical copy-paste errors preserved intentionally. - **Checksum Handling**: `CommandPacket.VerifyPacket` does **not** validate checksum correctness—only checks for `\r\n` termination. Checksum is computed but never checked for validity. - **Firmware Workaround**: `QueryCurrentPositions.WholePackage()` contains a hack to split the last position value if it contains a space (e.g., `"1.23 4.56"` → two values). This masks a firmware bug. - **Parameter Indexing**: `QuerySerialNumber` and `QueryDataAvailable` use `Parameter[1]` for the first data value (not `Parameter[0]`), since `Parameter[0]` holds the command name. This is consistent but non-intuitive. - **Data Conversion in `DownloadTestData`**: The conversion loop for `_Data` has a suspicious offset: `ByteArray[2 * i + i / _NumberOfChannels]` This implies a variable-length checksum per channel, which contradicts the comment "per sample checksum". Likely incorrect. - **Silent Error Handling**: `QuerySerialNumber.WholePackage()` catches exceptions during `GetParameter` but only logs via `e.ToString()` (no actual logging). Errors may go unnoticed. - **`DownloadTestData.Data` Type**: Returns `ushort[]` but `GetChannelData` converts to `short[]`. Users must be aware of signed/unsigned mismatch. - **`QueryArmAndTriggerStatus` Status Mapping**: `DataAvailable` state maps to all flags `false`, which may be counterintuitive (data available but not armed/recording/triggered). - **`QueryDataAvailable` Enum Mismatch**: Uses `Commands.QueryNumberOfLEDs` enum value but `"DUMPINFO"` command string—likely a typo preserved for compatibility. - **No Validation of Timeout**: `TimeoutMillisec` is passed to base class, but no validation or sanity checks are present in constructors.