.. _icd: ========================== Interface Control Document ========================== Copyright ========= Copyright Creare LLC 2017. This software specification is proprietary and should be considered confidential. Reproduction or distribution prohibited without written permission from Creare. Revision Log ============ .. csv-table:: Revision Log :header: "Date", "Author", "Changes" :widths: 15, 10, 75 :name: ICD Revision Log "2017/04/04", "WHF", "Added FIRMWARE_GET_CRC32 command description." "2017/03/22", "WHF", "Added GET_WELL_FAULTS command description." "2017/3/3", "MCR", "Added this revision log." "2018-06-21", "WHF", "Document pixel encoding in bulk USB stream." Introduction ============ This document describes the communication protocols used between the DMS controller (hereafter simply referred to as the DMS), and the host computer. It partially replicates information found in the header file, :ref:`dmsCodes.h`, found in the ‘Shared’ area of the source code tree. Every effort has been made to make these two documents agree, but in the case of disagreement dmsCodes.h, and thus the source code, prevail. .. _icd-usb-interface: USB Interface ============= Communication between the DMS and the host PC occurs over a USB 2.0, Full speed (12 Mbps) connection. Creare recommends, and our example code utilizes, Microsoft’s WinUSB driver system, but the interface is generic USB and so any low level USB access library, such as lib-usb, could be used. The vendor ID is currently 0xABCD. This is a bogus vendor ID, because at this time Creare is not registered with the USB Implementers Forum. However, it is adequate for non-public device deployment. The product ID is 0x7819. Two endpoints are defined. Endpoint 0 is the standard control endpoint required for all USB devices. The DMS makes use of this endpoint to receive commands and return results. Endpoint 1 is a standard bulk endpoint. This endpoint is used to stream raw data samples from the DMS to the host, for example in alignment mode. The DMS has no support for bulk streaming to the device. Note that in all cases, all data elements are transmitted and received in LSB (little endian) format. Endpoint 0 Commands =================== The DMS supports the commands shown in :numref:`Supported Commands Summary`. Note that these are ‘Vendor’ Device Requests; refer to Chapter 9 of the USB 2.0 specification. A ‘Read’ is defined here as the DMS sending control data back to the host (Device-to-host); a ‘Write’ is defined as the host sending additional data along with the command (Host-to-device). If the length is 0 the direction is immaterial. The function HI(x) takes the high order 16-bits of a 32-bit word x. Likewise, LO(x) takes the low order 16-bits. .. csv-table:: Supported Commands Summary :header: "Command", "Description", "R/W", "bRequest", "wValue", "wIndex", "wLength" :widths: 5, 5, 2, 2, 2, 2, 2 :name: Supported Commands Summary STATUS, Controller condition, R, 0x01, 0, 0, 12 ID, Build date and unique ID, R, 0x02, 0, 0, 48 CONFIG_GET, Read configuration data, R, 0x03, 0, 0, 24 CONFIG_SET, Write configuration data, W, 0x04, 0, 0, 24 CALIBRATE, Run a calibration process, R, 0x05, "1, 2, or 3", 0, 0 GET_CALIBRATION, Get calibration results, R, 0x06, 0, 0, 1688 STORE_CALIBRATION, Write current calibration to non-volatile memory, R, 0x07, 0, 0, 0 MONITOR_DISPENSE, Begin monitoring, R, 0x08, 0, 0, 0 GET_DISPENSE_DATA, Return results from monitoring, R, 0x09, HI(offset), LO(offset), (up to 4096) CLEAR_HISTORY, Remove the accumulated previous results used as reference, R, 0x0B, 0, 0, 0 SET_REFERENCE_DISPENSE, Set the last result as a baseline for comparison, R, 0x0C, 0, 0, 0 GET_WELL_FAULTS, Get data corresponding to well faults, R, 0x0D, 0, offset, (up to 4096) STREAM, Start / stop streaming of raw data from sensor, R, 0x10, 0 or 1, 0, 0 FIRMWARE_BLOCK, Send a block of firmware data, W, 0x20, HI(offset), LO(offset), (up to 512) FIRMWARE_PROGRAM, Cause the DMS to rewrite its FLASH based on the blocks sent, R, 0x21, HI(size), LO(size), 0 FIRMWARE_GET_CRC32, Cause the DMS to compute the 32-bit CRC of the firmware it has received, R, 0x22, HI(size), LO(size), 4 The commands are described in more detail below. .. _icd-status: Status ====== In response to this command, the DMS returns its current state of operation. This command should be used to poll the DMS (~10 Hz) to determine the result of other commands. .. csv-table:: Manual Control Data :header: "Data Item", "Field Lengths (bytes)" :widths: 8, 5 :name: Manual Control Data State (u32), 4 Flags (u32), 4 Last Reported Error (u32), 4 The following states are currently defined. .. csv-table:: Controller States :header: "Code", "State" :widths: 5, 10 :name: Controller States 0, OFF 1, INITIALIZATION 2, READY 3, CALIBRATION 4, MONITOR 5, STREAM The following flag bits are defined. .. csv-table:: Controller Status Bit Field :header: "Bits", "Status" :widths: 5, 10 :name: Controller Status Bit Field 0-3, RESERVED 4, Configuration Fail (Hardware Error) 5-19, RESERVED 20, Configuration Using Defaults 21-31, RESERVED The following error codes are currently defined. .. csv-table:: Error Codes :header: "Code", "Mnemonic", "Suggested Display Setting" :widths: 5, 10, 10 :name: Error Codes 0, DMS_ERR_NONE, "No error." 1, DMS_ERR_SENSOR_NOT_DARK, "Sensor is not dark." 2, DMS_ERR_INSUFFICIENT_BG_ILLUM, "Insufficient background illumination." 3, DMS_ERR_INSUFFICIENT_PEAKS, "8 peaks not found in calibration image." 4, DMS_ERR_CAL_NOT_CENTERED, "Calibration not centered on sensor." 5, DMS_ERR_ILLEGAL_STATE, "The DMS cannot accept that command at this time." 6, DMS_ERR_UNSUPPORTED_OPERATION, "The DMS does not support that operation." 7, DMS_ERR_MEMORY, "The DMS has insufficient memory to store the desired number of signals." 8, DMS_ERR_NO_VALID_REFERENCE, "User reference mode was indicated, but no user reference has been set." 9, DMS_ERR_STREAM_DIAMETER_UNSUPPORTED, "No thresholds are defined for this stream diameter." 10, DMS_ERR_NO_RECENT_HISTORY, "No dispense exists in the history to use for the user reference." 11, DMS_ERR_CALIBRATION_INVALID, "The data in calibration contain errors." 12-255, RESERVED, "" .. _icd-id: ID == This command causes the DMS to return the build date and time of its firmware, the unique ID associated with the processor, and the engineering version number. .. csv-table:: Identification Data :header: "Data Item", "Format", "Field Length (bytes)" :widths: 5, 10, 5 :name: Identification Data Build Date / Time, String(Mmm dd yyyy hh:mm:ss), 24 Unique ID, u32 x 4, 16 Engineering Version Number, "String, e.g. '1.0'", 8 .. _icd-config-get: Config Get ========== In response to the CONFIG_GET command, the DMS will return the current value of all configuration parameters. See :numref:`Configuration Data`. .. csv-table:: Configuration Data :header: "Data Item", "Field Length (bytes)" :widths: 10, 5 :name: Configuration Data "Stream Diameter mils, (u32)", 4 "Number of Dispenses (u32)", 4 "Dispense Time, msec (u32)", 4 "Dispense Period, msec (u32)", 4 "N Ref History (u32)", 4 "Ref Mode (u32)", 4 Please refer to the :ref:`Configuration Parameters` in the :ref:`firmware-spec` for the exact usage of these parameters. .. _icd-config-set: Config Set ========== The host may overwrite the configuration parameters with this command. The data provided should exactly match :numref:`Configuration Data`. .. _icd-calibrate: Calibrate ========= This command requests the DMS to perform a calibration operation. The DMS must be in the READY state. There are currently three operations defined, which the host may select via the wValue control parameter; see :numref: `Calibration Operations`. .. csv-table:: Calibration Operations :header: "Operation", "wValue" :widths: 10, 5 :name: Calibration Operations RESERVED, 0 Get Dark Level, 1 Set Background, 2 Calibrate, 3 RESERVED, 4-65535 See :ref:`calibration` in the :ref:`firmware-spec` for the full details of these operations. After the operation is commanded, :ref:`icd-status` should be polled to observe the return of the DMS to the READY state. If the error code is zero, then the calibration operation was successful; otherwise there was a problem that requires operator attention. .. _icd-get-calibration: Get Calibration =============== The DMS returns the current calibration in response to this command. This is primarily for debugging purposes. The calibration has the format shown in :numref:`Calibration Data`. .. csv-table:: Calibration Data :header: "Data Item", "Field Length (bytes)" :widths: 10, 5 :name: Calibration Data Dark Level (u16), 2 Background (384 * u16), 768 Pixel Range (2 * u16), 4 Bin Edges (9 * u16), 18 Cal Image (384 * u16), 768 Cal Center (8 * f32), 32 Cal Sigma (8 * f32), 32 Cal Amp Scale (8 * f32), 32 Cal Lateral Scale (8 * f32), 32 Cal Sigma Scale (8 * f32), 32 Please refer to the :ref:`calibration` section of the :ref:`firmware-spec` for the meaning of these calibration elements. .. _icd-store-calibration: Store Calibration ================= After the calibration is computed, it is held in RAM only. After this command is executed the calibration is written to non-volatile memory. .. _icd-monitor-dispense-icd: Monitor Dispense ================ This command instructs the DMS to begin monitoring the sensor for a dispense operation. Assuming it was in the READY state when the command was received, it will proceed to the MONITOR state, and wait for triggers. When the DMS has returned to the READY state, the results are ready and can be requested. .. _icd-get-dispense-data: Get Dispense Data ================= After monitoring is complete, this command causes the DMS to emit the last results of the operation. 4096 bytes may be captured with each read, which means that some fields ('signals', in particular) will require several reads to capture fully. To use this command most effectively, instantiate an instance of the DMS_DISPENSE_DATA structure. Then, to receive a particular field, use code similar to the following: .. code-block:: C uint32_t offsetBytes = offsetof(dmsDispenseData.info); ctrl_read( DMS_CMD_GET_DISPENSE_DATA, // bReq HI(offsetBytes), // wValue LO(offsetBytes), // wIndex &dmsDispenseData.info, // data sizeof(dmsDispenseData.info) // nBytes ); To receive larger blocks, simply loop, incrementing offsetBytes each time by the number of characters received. .. _icd-clear-history: Clear History ============= When calculation features used for fault detection, several features are normalized by the median of results from previous plates. This is useful when the baseline has changed, for example due to the replacement of the dispense cartridge. .. _icd-set-reference-dispense: Set Reference Dispense ====================== If the 'Ref Mode' configuration parameter is non-zero, a user reference will be used. This command makes the most recent dispense the user reference. .. _icd-get-well-faults: Get Well Faults =============== This command is used to return the data corresponding to well faults. For each dispense in the monitor event (available through n_dispenses in the configuration data structure) there will be eight u32s, each corresponding to one channel. Each two bits correspond to a fault indication from the Fault Categories table. The two LSB correspond to Fault Description 1, the next two to Fault Description 2, up to Fault Description 15. The upper two MSB should be zero after a successful monitoring operation. Each two bits correspond to a fault severity level: 0, no fault; 1, notice; 2, warning; and 3, error. .. _icd-stream: Stream ====== This command controls raw data streaming. The wValue parameter controls the streaming: 0 halts streaming, 1 begins streaming, and all other values are reserved. After receiving this command with a wValue of 1, the DMS will begin streaming the raw data from the sensor to the host at the full, 1kHz rate, on Bulk Transfer endpoint 1. The DMS will stream packets of the form described in :numref:`Stream Packet Format` until commanded to stop. Note the DMS must be in the READY state to use this command. .. csv-table:: Stream Packet Format :header: "Data Item", "Field Length (bytes)" :widths: 5, 10 :name: Stream Packet Format Header (u32), 4 Packed Samples (u32), "768 (512 pixels, 12 bits per pixel, packed into 192 32-bit words)" This picture illustrates the mapping of bits within the 8-bit bytes of the stream data to the corresponding bits within the equivalent stream of 12-bit pixels. .. image:: images/Mapping_of_Stream_Data_Bytes_to_Pixels.png :width: 407 However, to implement in this way would be naïve. Modern processors are much more efficient with 32-bit word sizes, and so we implement on that block size. The resulting mapping is straightforward. .. image:: images/Mapping_of_Stream_Words_to_Pixels.png :width: 1022 The header consists of two parts. The upper 16 bits holds the value 0x781C, which may be used to scan for the start of a packet if synchronization is lost. The lower 16 bits contain trigger status. Bit 0 is the pump trigger, while bit 1 is the plate trigger. Bits 2 through 15 are reserved. .. _icd-firmware-block: Firmware Block ============== In order to update the firmware on the DMS, it needs to be transferred to the DMS's memory using this command. Up to 512 bytes can be sent with each transfer. The offset of each block in bytes are the wValue and wIndex parameters. Only send binary program files (e.g. DMS.bin). .. _icd-firmware-program: Firmware Program ================ Once the program has been successfully transmitted to the DMS in its entirety, this command may be executed to copy the program from RAM into the device's FLASH. The device will then be rebooted. .. _icd-firmware-get-crc: Firmware Get CRC-32 =================== Once the program has been successfully transmitted to the DMS in its entirety, in response to this command the DMS will compute and transmit the CRC-32 of the bytes which have sent which comprise the Firmware. This can be compared against the local CRC of the firmware as a verification step before programming it to the DMS's FLASH. .. _icd-dmsCodes.h: dmsCodes.h ========== The current version of dmsCodes.h is included here for reference. Note the horizontal scroll bar at the bottom, if you need to see the end of the lines. Sorry, this is a pain! .. literalinclude:: ../Shared/include/dmsCodes.h :language: c :tab-width: 2 .. *** NOTE: the following reduntant directive is used for subset builds. .. literalinclude:: ../../Shared/include/dmsCodes.h :language: c :tab-width: 2