Near-Infrared Spectrometer Serial Command Protocol
SummaryA guide to the low-level serial command protocol of Pynect NIR spectrometers, covering the data frame structure, checksum calculation, common commands and the scan-and-read workflow for controlling the device without an SDK.
Near-Infrared Spectrometer Serial Command Protocol
Overview
Pynect near-infrared spectrometer modules and spectrometers support low-level command communication over a USB virtual serial port (HID). Mastering the serial command protocol allows you to interact with the device directly without using an SDK, making it suitable for embedded system development, custom host-software development and similar scenarios. This article describes the data frame structure, checksum mechanism and common operating commands of serial communication.
1. Data Frame Structure
Each command consists of a fixed-format data frame (packet) with the following structure:
| Member | Start index | Bytes | Description |
|---|---|---|---|
| start bytes | 0 | 4 | Frame start marker: 0x41 0x42 0x43 0x44 (ASCII "ABCD") |
| checksum | 4 | 4 | Checksum (excluding start/trailer bytes) |
| flag | 8 | 1 | Flag byte, fixed 0xC0 |
| sequence byte | 9 | 1 | Sequence number (used to match requests and responses) |
| length | 10 | 2 | Data length = bytes of command(2) + data(N) |
| command | 12 | 2 | Command code |
| data | 14 | N | Command payload data (may be empty) |
| trailer bytes | end | 4 | Frame end marker: 0x44 0x43 0x42 0x41 (ASCII "DCBA") |
Example frame (configure scan parameters):
41 42 43 44 ← start bytes
5D 00 00 00 ← checksum
C0 ← flag
00 ← sequence byte
1E 00 ← length = 30
18 02 ← command (NNO_CMD_CONFIG_SCAN)
04 04 02 00 ... ← data (28 bytes)
44 43 42 41 ← trailer bytes
2. Checksum Calculation
The checksum is used to verify the integrity of data transmission. It is calculated by summing all bytes from the flag to the end of the data (excluding the start bytes and trailer bytes) and taking the low 4 bytes. After receiving the data, the receiver recomputes the checksum and compares it with the checksum field in the frame; a mismatch indicates a transmission error.
3. Common Operating Commands
3.1 Configure Scan Parameters (NNO_CMD_CONFIG_SCAN)
Command code: 0x18 0x02
Configures the spectrometer's scan parameters, including integration time, gain, scan mode and more. After sending, the device returns an identical command frame as confirmation.
Example send frame:
41 42 43 44 5D 00 00 00 C0 00 1E 00 18 02
[28 bytes config data]
44 43 42 41
3.2 Perform Scan (NNO_CMD_PERFORM_SCAN)
Command code: 0x16 0x02
Triggers one spectrum scan. This command has no data field (length = 2).
Send frame:
41 42 43 44 DA 00 00 00 C0 00 02 00 16 02 44 43 42 41
Return frame: The device returns a scan data packet whose data contains wavelength, intensity and other information.
3.3 Get Scan Status (NNO_CMD_SCAN_GET_STATUS)
Command code: 0x19 0x02
Queries whether the scan is complete. The returned data payload:
| Return value | Meaning |
|---|---|
0x01 |
Scan complete, data ready |
| empty | Still scanning; continue polling |
Send frame:
41 42 43 44 DD 00 00 00 C0 00 02 00 19 02 44 43 42 41
3.4 Get Returned Data Length (NNO_CMD_FILE_GET_READSIZE)
Command code: 0x2D 0x00
Reads the total length (bytes) of the data packet returned by the current scan, for subsequent chunked reading.
3.5 Get Scan Data (NNO_CMD_FILE_GET_DATA)
Command code: 0x2E 0x00
Reads the complete scan data packet. The returned data contains the following information:
| Field | Description |
|---|---|
| header_version | Protocol version number |
| serial_number | Device serial number (8-byte ASCII) |
| adc_data_length | Total ADC data length |
| pga | Current gain multiplier |
| scan_config | Scan configuration parameters |
| wavelength[ ] | Wavelength array (864 double values) |
| intensity[ ] | Intensity array (864 int values) |
| length | Number of valid data points (usually 228) |
4. Scan Data Reading Workflow
The complete scan and data-reading workflow is as follows:
1. Send CONFIG_SCAN → configure scan parameters
2. Send PERFORM_SCAN → trigger a scan
3. Poll GET_STATUS → wait for the scan to complete (data[0] == 0x01)
4. Send GET_READSIZE → get the data packet length
5. Send GET_DATA → read the complete data packet
6. Parse wavelength[] and intensity[] → obtain the spectral data
5. Integration Time and Pixel Width Conversion
Integration time (exposure time)
The integration time index starts from 0, and its relationship to the real time is:
| index | Integration time |
|---|---|
| 0 | 0.635 ms |
| 1 | 1.27 ms |
| 2 | 2.54 ms |
| 3 | 5.08 ms |
| ... | doubles each step |
Pixel width (width_px)
The pattern width is calculated in DMD pixels (px). For the standard wavelength optical engine (900-1700 nm):
$$1\text{ px} \approx 1.1709\text{ nm} = \frac{800\text{ nm}}{854\text{ px} \times 80\%}$$
| width_px | Corresponding spectral width |
|---|---|
| 5 px | ≈ 5.85 nm |
| 6 px | ≈ 7.03 nm |
| 7 px | ≈ 8.20 nm |
For extended-wavelength optical engines (1350-2150 nm / 1600-2400 nm), 1 px ≈ 1 nm.
6. FAQ
Structure Alignment
When parsing data packets in C/C++ development, pay attention to byte alignment of structures. The following structure contains members of different sizes (uint8_t, uint16_t, char[ ]), so the compiler may automatically insert padding bytes that cause parsing offsets:
struct ScanConfig {
uint8_t scan_type;
uint16_t scanConfigIndex; // may be at offset 2 instead of offset 1
char serial_number[8];
char config_name[40];
uint16_t num_repeats;
uint8_t num_sections;
};
Solution: Use #pragma pack(1) or __attribute__((packed)) to force 1-byte alignment, or manually parse the offset positions field by field instead of relying on sizeof.
This article was compiled by Pynect.