-
Notifications
You must be signed in to change notification settings - Fork 3
06 ‐ DTE commands
The DTE (Data Terminal Equipment) protocol is the primary interface for configuring and querying the tracker. It is used by pylinkit, the LinkIt GUI tool, and any BLE/UART terminal to communicate with the firmware.
$COMMAND#LEN;PAYLOAD\r
| Field | Description |
|---|---|
$ |
Start delimiter |
COMMAND |
Command name (4-6 uppercase characters) |
# |
Length separator |
LEN |
Payload length in hexadecimal (3 digits) |
; |
Payload separator |
PAYLOAD |
Command-specific payload (comma-separated) |
\r |
Carriage return terminator |
Success:
$O;COMMAND#LEN;PAYLOAD\r
Error:
$N;COMMAND#LEN;ERROR_CODE\r
| Code | Name | Description |
|---|---|---|
| 0 | OK | Success |
| 1 | INCORRECT_COMMAND | Unknown command |
| 2 | INCORRECT_DATA | Invalid data |
| 3 | MISSING_ARGUMENT | Required argument missing |
| 4 | VALUE_OUT_OF_RANGE | Value exceeds allowed range |
| 5 | MESSAGE_TOO_LARGE | Payload exceeds max length (0xFFF) |
| 6 | PARAM_KEY_UNRECOGNISED | Unknown parameter key |
| 7 | BAD_FORMAT | Malformed request |
| 8 | DATA_LENGTH_MISMATCH | Payload length doesn't match #LEN |
| 9 | UNEXPECTED_ARGUMENT | Too many arguments |
| 10 | INVALID_ACCESS_CODE | Wrong SECUR access code |
| Command | Description |
|---|---|
| Parameter Commands | |
| PARML | List all parameter keys |
| PARMR | Read parameters by key |
| PARMW | Write parameters by key |
| STATR | Read status/telemetry parameters |
| Device Commands | |
| PROFR | Read profile name |
| PROFW | Write profile name |
| FACTW | Factory reset |
| RSTBW | Reboot device |
| RSTVW | Reset variable (TX/RX counters) |
| SECUR | Security access authentication |
| RTCW | Set device RTC |
| DUMPM | Dump raw memory region |
| DUMPD | Dump sensor log data (CSV) |
| ERASE | Erase sensor log data |
| Argos/Satellite Commands | |
| PASPW | Write pass prediction (AOP) data |
| SATTX | Manual Argos satellite transmission |
| SATDP | Start periodic Doppler TX calibration |
| SMDDFU | SMD module firmware update |
| SMDTST | SMD SPI connectivity test |
| SATVF | Verify comm module credentials (Argos or LoRa) |
| Sensor Commands | |
| SENSR | Read live sensor values |
| SCALW | Write sensor calibration |
| SCALR | Read sensor calibration |
| PWRON | Power on/off components |
| SWSST | Read SWS calibration status |
| SWSTST | Start/stop SWS test mode |
| SWSCAL | Start/cancel LED-assisted SWS air/water calibration |
| SWSSTATS | Read (or read+clear) persistent SWS diagnostic counters |
| GNSSI | Read GNSS module info |
| GNSSA | Read GNSS almanac status |
| GNSSBCKP | Trigger / stop the V_BCKP coin-cell charge mode |
| RF Test Commands | |
| COMCW | Start/stop CW RF emission (SMD / LoRa) for certification / antenna test |
| LoRa/Bridge Commands | |
| LORATX | Manual LoRa test TX |
| GNSSBR | GNSS bridge mode (USB ↔ u-blox M10Q UART) |
| KIMBR | KIM2 bridge mode (USB ↔ CLS KIM2 AT passthrough) |
| LORABR | LoRa bridge mode (USB ↔ RAK3172 AT passthrough) |
Parameter keys are 5 characters: 3-letter prefix + 2-digit number. The third character indicates the type:
-
P -- Configurable parameter (read/write). Returned by
PARMRwith no arguments. -
T -- Telemetry / status value (read-only). Returned by
STATRwith no arguments.
| Prefix | Group | Description |
|---|---|---|
ARP |
Argos Params | Argos TX configuration |
ART |
Argos Telemetry | Argos counters and timestamps |
GNP |
GNSS Params | GNSS acquisition and filtering |
UNP |
Underwater Params | Underwater detection and sampling |
LBP |
Low Battery Params | Low battery mode configuration |
ZOP |
Zone Params | Geofencing zone configuration |
PPP |
Pass Predict Params | Prepass algorithm settings |
PRP |
Pressure Params | Pressure sensor configuration |
AXP |
Accelerometer Params | Accelerometer configuration |
THP |
Thermistor Params | Thermistor sensor configuration |
STP |
Sea Temp Params | Sea temperature sensor |
PHP |
pH Params | pH sensor configuration |
LTP |
Light Params | Ambient light sensor |
CDP |
CDT Params | Conductivity-Depth-Temperature |
CAP |
Camera Params | Camera trigger configuration |
CTP |
Certification Params | TX certification test mode |
LDP |
LED Params | LED mode configuration |
PWP |
Power Params | TPL5111 wakeup management |
DBP |
Debug Params | Debug output configuration |
IDT |
Identity Telemetry | Device model, HW/FW version |
IDP |
Identity Params | Device IDs, profile name |
POT |
Power Telemetry | Battery SOC, voltage |
SYT |
System Telemetry | System status (RTC, etc.) |
LRP |
LoRa Params | LoRa RAK3172 configuration |
LRT |
LoRa Telemetry | LoRa counters and status |
$PARML#000;\r
→ $O;PARML#LEN;IDP12,IDT06,IDT02,IDT03,ART01,ART02,...\r
Returns all implemented DTE keys. The exact set depends on the build configuration.
Read one or more values by key, or all "P"-type parameters when called empty.
$PARMR#000;\r # Read all configurable parameters
$PARMR#00F;GNP01,ARP05,ARP01\r # Read specific parameters
→ $O;PARMR#01B;GNP01=1,ARP05=60,ARP01=2\r
Write one or more key=value pairs. Read-only parameters are silently skipped. Triggers CONFIG_UPDATED after saving.
$PARMW#011;GNP01=1,ARP05=120\r
→ $O;PARMW#000;\r
Error 4 (VALUE_OUT_OF_RANGE) if a value exceeds the parameter's allowed range.
Previously, a permitted_values={0U} enum (e.g. SMD_DEGRADED_MODE accepting only 0) made the DTE decoder throw DTE_PROTOCOL_VALUE_OUT_OF_RANGE during PARMW decoding whenever the GUI wrote the slot back at its current value (autofallback engages SAFE by setting it to 1; later PARMW with SMP00=1 would throw). The throw escapes the per-slot try/catch in PARMW_REQ because the decoder runs BEFORE that loop, and was only caught at the top-level handler which cleared the response. GUI then saw a timeout and "lost" the whole config read/write session.
Fix: rejection now happens via the explicit check in PARMW_REQ (rejected via rejected_keys without throwing). Non-zero writes are reported and every other slot in the batch still applies. The permitted_values field is kept for declarative documentation.
SMD_DEGRADED_MODE (SMP00) flipped from read-only to writable. PARMW SMP00=0 is now accepted (clears SAFE mode immediately, next TX uses FAST). PARMW SMP00=1 is rejected — manual SAFE engagement remains under exclusive autofallback control (3 consecutive cascade errors). Lazy sync of the runtime flag at the top of SmdSat::send() makes the change take effect on the next TX without requiring a reboot.
| Key | Name | Type | Range | Description |
|---|---|---|---|---|
| IDP12 | ARGOS_DECID | UINT | 0-4294967295 | Argos decimal ID |
| IDT06 | ARGOS_HEXID | HEX | 0-FFFFFFFF | Argos hex ID |
| IDP11 | PROFILE_NAME | TEXT | - | Profile name |
| ARP05 | TR_NOM | UINT | 30-1200 | TX repetition (seconds) |
| ARP01 | ARGOS_MODE | ENUM | 0-4 | Argos operating mode |
| GNP01 | GNSS_EN | BOOL | 0/1 | GNSS enable |
| GNP05 | GNSS_ACQ_TIMEOUT | UINT | 10-600 | GNSS acquisition timeout (s) |
| UNP01 | UNDERWATER_EN | BOOL | 0/1 | Underwater detection enable |
| LBP01 | LB_EN | BOOL | 0/1 | Low battery mode enable |
| LBP02 | LB_THRESHOLD | UINT | 0-100 | Low battery threshold (%) |
| DBP01 | DEBUG_OUTPUT_MODE | ENUM | 0-3 | 0=UART, 1=USB_CDC, 2=BLE_NUS, 3=NONE |
Identical to PARMR but filters for "T"-type keys when called empty.
$STATR#000;\r # Read all telemetry
$STATR#00A;ART02,IDT03\r # Read specific keys
→ $O;STATR#013;ART02=0,IDT03=V0.1\r
| Key | Name | Description |
|---|---|---|
| IDT02 | DEVICE_MODEL | Device model |
| IDT03 | FW_APP_VERSION | Firmware version |
| IDT04 | HW_VERSION | Hardware version |
| IDT10 | DEVICE_DECID | Device decimal ID |
| ART01 | LAST_TX | Last transmission timestamp |
| ART02 | TX_COUNTER | Transmit counter |
| ART03 | ARGOS_AOP_DATE | AOP bulletin date |
| POT03 | BATT_SOC | Battery state of charge (%) |
| POT06 | BATT_VOLTAGE | Battery voltage (V) |
| SYT01 | RTC_CURRENT_TIME | Live RTC value (Unix timestamp) |
$PROFR#000;\r
→ $O;PROFR#018;Profile Name For Tracker\r
Max 128 characters.
$PROFW#018;Profile Name For Tracker\r
→ $O;PROFW#000;\r
Restore all parameters to factory defaults. Device reboots after response.
$FACTW#000;\r
→ $O;FACTW#000;\r
$RSTBW#000;\r
→ $O;RSTBW#000;\r
Reset a runtime counter to zero.
| Index | Variable |
|---|---|
| 1 | TX_COUNTER |
| 2 | BOOT_COUNTER (EXTERNAL_WAKEUP builds only) |
| 3 | ARGOS_RX_COUNTER |
| 4 | ARGOS_RX_TIME |
$RSTVW#001;1\r
→ $O;RSTVW#000;\r
Authenticate for privileged operations (OTA, etc.). Accepts code 0x12345678 or the device's ARGOS_DECID.
$SECUR#008;12345678\r
→ $O;SECUR#000;\r
Set the device RTC to a Unix timestamp. Also updates LAST_KNOWN_RTC (PWP06) on all boards for RTC persistence across power cycles.
$RTCW#00A;1708444800\r
→ $O;RTCW#000;\r
Read back via: $STATR#005;SYT01\r
Read raw memory as base64. Max length: 0x500.
$DUMPM#007;100,200\r
→ $O;DUMPM#LEN;<base64_data>\r
Paginated CSV dump of sensor logs. Call repeatedly until mmm == MMM.
| d_type | Log Type |
|---|---|
| 0 | System (system.log) |
| 1 | GNSS |
| 2 | ALS |
| 3 | PH |
| 4 | RTD |
| 5 | CDT |
| 6 | Camera |
| 7 | AXL (Accelerometer) |
| 8 | Pressure |
| 9 | Thermistor |
| A | TSYS01 |
| B | SWS (saltwater switch log) |
| C | Mortality (RSPB) |
$DUMPD#001;1\r
→ $O;DUMPD#LEN;000,002,<base64_csv_data>\r
Response: mmm (page index), MMM (max page index), data (base64 CSV). Max 8 entries per page.
| log_type | Target |
|---|---|
| 1 | GNSS |
| 2 | System |
| 3 | ALL |
| 4-12 | ALS, PH, RTD, CDT, Camera, AXL, Pressure, Thermistor, TSYS01 |
| 13 | SWS |
| 14 | Mortality |
$ERASE#001;3\r
→ $O;ERASE#000;\r
Upload base64-encoded AOP satellite pass prediction data. Updates ARGOS_AOP_DATE (ART03).
$PASPW#LEN;<base64_encoded_prepass_data>\r
→ $O;PASPW#000;\r
Verify: $PARMR#005;ART03\r
Trigger a test satellite transmission. The response is asynchronous (sent after TX completes via KineisEventTxComplete).
Two modes are supported:
Uses the radioconf already saved in the device config (ARP51=LDK, ARP52=LDA2, ARP53=VLDA4).
SATTX,<modulation>,<size>[,<tcxo>]
| Arg | Type | Description |
|---|---|---|
| modulation | UINT | 0=LDK, 1=LDA2, 2=VLDA4 |
| size | UINT | Payload size in bytes |
| tcxo | UINT | TCXO warmup time in seconds (optional, default 0) |
Example:
$SATTX#004;1,10\r # LDA2, 10 bytes, stored radioconf
$SATTX#006;0,16,5\r # LDK, 16 bytes, TCXO warmup 5s
Pass a radioconf hex string directly (same format as ARP51/ARP52/ARP53).
SATTX,<modulation>,<radioconf>,<size>[,<tcxo>]
| Arg | Type | Description |
|---|---|---|
| modulation | UINT | 0=LDK, 1=LDA2, 2=VLDA4 |
| radioconf | TEXT | 32-character hex radioconf string |
| size | UINT | Payload size in bytes |
| tcxo | UINT | TCXO warmup time in seconds (optional, default 0) |
Example:
$SATTX#025;1,0123456789ABCDEF0123456789ABCDEF,10\r
$SATTX#027;2,FEDCBA9876543210FEDCBA9876543210,20,3\r
The firmware auto-detects the mode by the length of the second argument: if it is longer than 2 characters it is treated as a custom radioconf string, otherwise it is parsed as the packet size (stored radioconf mode).
| Modulation | ID | Max Size |
|---|---|---|
| LDK | 0 | 16 bytes (128 bits) |
| LDA2 | 1 | 24 bytes (192 bits) — last byte is firmware-embedded CRC8 |
| VLDA4 | 2 | 3 bytes (24 bits) |
Size must be between 1 and the maximum for the selected modulation.
| Condition | Error Code |
|---|---|
| Missing arguments (< 2) | 8 (MISSING_ARGUMENT) |
| Invalid modulation (> 2) | 5 (INCORRECT_DATA) |
| Size = 0 or exceeds max | 5 (INCORRECT_DATA) |
| Empty radioconf (stored not configured, or custom empty) | 5 (INCORRECT_DATA) |
| No satellite device available | 5 (INCORRECT_DATA) |
$O;SATTX#000;\r
Start periodic Doppler TX at TR_NOM interval. Runs until device reset.
$SATDP#000;\r
→ $O;SATDP#000;\r
LED feedback (commit 143aedc9): SATDP bypasses ArgosTxService and calls smd_sat_instance->send() directly, so the operational FSM never emits SERVICE_ACTIVE for ARGOS_TX and the MAGENTA-on-TX LED dispatch in gentracker.cpp is skipped. The DTE handler now dispatches SetLEDArgosTX / SetLEDArgosTXComplete at every Doppler send and KineisEvent so the bench operator sees the same visual cue as a deployed Argos transmission. cert_tx_active() short-circuits the LED_MODE_GUARD, so the flash happens regardless of LED_MODE.
Manage SMD module firmware updates over SPI. Only on ARGOS_SMD=ON builds.
| Action | Value | Description |
|---|---|---|
| ENTER | 0 | Enter DFU (bootloader) mode |
| EXIT | 1 | Exit DFU mode |
| STATUS | 2 | Query DFU mode state |
| UPDATE | 3 | Trigger firmware update |
| INFO | 4 | Get bootloader info (DFU mode only) |
| VERSION | 5 | Get firmware version (app mode only) |
$SMDDFU#001;5\r
→ $O;SMDDFU#LEN;0,0,0,v1.2.3\r
Response: status (0=OK), dfu_mode (0/1), progress (0-100%), info (text).
Run full SPI diagnostic against the SMD module.
$SMDTST#000;\r
→ $O;SMDTST#LEN;<test_results_text>\r
Read credentials back from the communication module hardware and compare with config store values. Auto-detects the module type (Argos satellite or LoRa).
Optional force re-write: $SATVF#001;1\r → if hardware differs from config
store, re-writes credentials and returns the post-write state (field forced=1).
$SATVF#000;\r # read-only verify
$SATVF#001;1\r # verify + force re-write if mismatch
→ $O;SATVF#LEN;id,addr,seckey,radioconf,match,forced\r
| Field | Type | Description |
|---|---|---|
| id | uint | DEC_ID read from satellite module hardware |
| addr | uint | ADDRESS read from satellite module hardware |
| seckey | text | Security key read from satellite module hardware (hex) |
| radioconf | text | Radio config read from satellite module hardware (hex) |
| match | uint | 1 = hardware matches config store, 0 = mismatch |
Compares: ARGOS_DECID (IDP12) and ARGOS_HEXID (IDT06).
If match=0, credentials will be synced to hardware automatically at the next TX (dirty flag mechanism).
| Field | Type | Description |
|---|---|---|
| id | uint | 0 (not applicable for LoRa) |
| addr | uint | NJM mode (0=ABP, 1=OTAA) |
| seckey | text | Credential summary: NJM=x DEVEUI=xxx APPEUI=xxx APPKEY=xxx (OTAA) or NJM=x DEVEUI=xxx DEVADDR=xxx (ABP) |
| radioconf | text |
OTAA or ABP
|
| match | uint | 1 = module matches config store, 0 = mismatch |
Compares (case-insensitive hex):
-
OTAA (NJM=1):
DEVEUI+APPEUI+APPKEY -
ABP (NJM=0):
DEVEUI+DEVADDR(session keys NWKSKEY/APPSKEY are write-only on RAK3172, cannot be read back)
Auto-wake (LoRa only): since firmware commit
21f89ee9, SATVF automatically boots the RAK3172 if it is powered off (e.g.LORA_LP_MODE=0shutdown mode or underwater power-off). Boot takes ~1.5 s + ~500 ms AT ping → response returns in under 3.5 s worst case even from a cold start. After the read, the module is powered off again to preserve idle consumption.No need to issue
LORATXfirst to wake the module — SATVF handles it.This also applies to
SMDDFU 5(version query) andCOMCWstart.
SMD/KIM2: the module must already be powered on (e.g. during a TX cycle) or use
$PWRON#001;3\rto bring it up first.
Live sensor reading. Bitmask selects which sensors to read.
Args: sensors_bitmask (UINT), timeout_s (UINT, reserved for future GNSS acquisition).
| Bit | Value | Sensor | Fields |
|---|---|---|---|
| 0 | 0x01 | Battery | voltage (mV), SOC (%) |
| 1 | 0x02 | Pressure | pressure (bar), temperature (°C), altitude (m) |
| 2 | 0x04 | GNSS | lat, lon, HDOP, num_sv (cached last fix) |
| 3 | 0x08 | Accelerometer | X, Y, Z (g), temperature (°C), activity (0-255) |
| 4 | 0x10 | Thermistor | temperature (°C) |
| 5 | 0x20 | Sea Temperature | temperature (°C) |
| 6 | 0x40 | ALS (Light) | lux |
| 7 | 0x80 | pH | pH value |
Use 255 (0xFF) for all sensors.
$SENSR#004;255,10\r
→ $O;SENSR#LEN;3700,80,1.013,22.5,45.2,48.8566,-2.3522,1.2,8,0.01,-0.02,0.98,23.1,42,36.5,0.0,0.0,0.0,31\r
Response fields (19 total):
| # | Field | Type | Unit | Description |
|---|---|---|---|---|
| 1 | batt_mv | UINT | mV | Battery voltage |
| 2 | batt_soc | UINT | % | Battery state of charge |
| 3 | pressure | FLOAT | bar | Barometric pressure |
| 4 | temperature | FLOAT | °C | Pressure sensor temperature |
| 5 | altitude | FLOAT | m | Barometric altitude |
| 6 | lat | FLOAT | ° | Latitude (cached GPS) |
| 7 | lon | FLOAT | ° | Longitude (cached GPS) |
| 8 | hdop | FLOAT | - | Horizontal DOP (99.9 = no fix) |
| 9 | num_sv | UINT | - | Number of satellites |
| 10 | accel_x | FLOAT | g | Accelerometer X axis |
| 11 | accel_y | FLOAT | g | Accelerometer Y axis |
| 12 | accel_z | FLOAT | g | Accelerometer Z axis |
| 13 | accel_temp | FLOAT | °C | Accelerometer temperature |
| 14 | activity | UINT | 0-255 | BMA400 activity score |
| 15 | thermistor_temp | FLOAT | °C | Thermistor body temperature |
| 16 | sea_temp | FLOAT | °C | Sea temperature (RTD/TSYS01) |
| 17 | als_lux | FLOAT | lux | Ambient light |
| 18 | ph | FLOAT | - | pH value |
| 19 | sensor_status | UINT | bitmask | Status: bit set = sensor OK |
sensor_status bitmask: Each bit corresponds to the same sensor as the request bitmask. A bit is set (1) if the sensor was read successfully, clear (0) if it failed (not compiled, not enabled, or hardware error).
Example: requested 0xFF (all), got sensor_status=0x1F (31) → bits 0-4 set = battery, pressure, GNSS, accel, thermistor OK. Bits 5-7 clear = sea temp, ALS, pH not available (not compiled in this build).
Backward compatibility: The first 15 fields are identical to the previous format. Fields 16-19 are appended. Old parsers that only read 15 fields will continue to work.
Args: sensor_id (0-7), offset, value (float).
| ID | Sensor |
|---|---|
| 0 | AXL (Accelerometer) |
| 1 | PRS (Pressure) |
| 2 | ALS (Ambient Light) |
| 3 | PH |
| 4 | RTD (Sea Temperature) |
| 5 | CDT |
| 6 | MCP47X6 (DAC) |
| 7 | THERMISTOR |
$SCALW#00D;1,0,1013.250000\r
→ $O;SCALW#000;\r
AXL (sensor_id=0):
| Offset | SCALW (write) | SCALR (read) |
|---|---|---|
| 0 | Set X offset (g) | — |
| 1 | Set Y offset (g) | Read calibrated X (g) |
| 2 | Set Z offset (g) | Read calibrated Y (g) |
| 3 | Auto-calibrate (value ignored, measures 200 samples) | Read calibrated Z (g) |
| 5 | — | Read saved X offset (g) |
| 6 | Save offsets to flash (value ignored) | Read saved Y offset (g) |
| 7 | — | Read saved Z offset (g) |
Auto-calibrate (offset=3): device must be on a flat, level surface. Firmware measures 200 samples, computes average X/Y/Z, and stores as offsets. Z targets 1.0g at rest.
PRS (sensor_id=1):
| Offset | SCALW (write) | SCALR (read) |
|---|---|---|
| 0 | Sea level pressure in hPa (default 1013.25) | Current sea level pressure (hPa) |
| 1 | Temperature offset in °C (default 0.0) | Current temperature offset (°C) |
THERMISTOR (sensor_id=7):
| Offset | SCALW (write) | SCALR (read) |
|---|---|---|
| 0 | Reset calibration (value ignored) | Current calibration offset (°C) |
| 1 | Calibrate at known temperature in °C (firmware measures 10 samples, computes offset) | Current live temperature (°C) |
Example: thermistor reads 22.3°C but the reference thermometer shows 24.0°C. Send $SCALW#009;7,1,24.0\r → firmware computes offset = +1.7°C and saves.
Args: sensor_id (0-7), offset.
$SCALR#003;1,0\r
→ $O;SCALR#00A;1013.250000\r
If a sensor or offset is not implemented, SCALR returns 0.0 (not an error).
| Value | Component |
|---|---|
| 0 | ALL (GNSS + sensors + satellite) |
| 1 | GNSS (also enables sensor power rail) |
| 2 | SENSORS (power rail only) |
| 3 | SATELLITE (also enables sensor power rail) |
| 4 | OFF (all components) |
$PWRON#001;3\r
→ $O;PWRON#000;\r
Read the Salt Water Switch analog state. Only on builds with SWS_ADC.
$SWSST#000;\r
→ $O;SWSST#LEN;2048,3500,2800,50,2750,2760,1,0,300\r
Response fields (9): air, water, threshold, hysteresis, raw_adc, filtered_adc, calibrated, underwater, time_in_state.
Start (1) or stop (0) SWS test with LED feedback (Blue=underwater, Yellow=surface).
$SWSTST#001;1\r
→ $O;SWSTST#001;1\r
LED-assisted air/water baseline calibration. Used at deployment time to teach the device the correct air/water ADC thresholds for the actual mounting + electrode geometry. Only on builds with ENABLE_SWS_ANALOG=1.
- Device must be in ConfigurationState (reed-switch 3 s or BLE connected).
- Hold the tracker in air (electrode dry).
- Issue
$SWSCAL#001;1\rto start. The synchronous response carries the current snapshot (status=0 initially). - The firmware samples air for ~5 s while flashing LED.
- Submerge the tracker in saltwater (or in the deployment water) when LED indicates.
- Firmware samples water for ~5 s.
- When done, an async response is emitted with
status=1(success) orstatus=2(failure). The GUI must listen for this second frame. - The new calibration is persisted to flash (
SWS.CAL) and is effective immediately.
$SWSCAL#001;1\r # Start guided calibration
$SWSCAL#001;0\r # Cancel an in-progress calibration
| Arg | Type | Description |
|---|---|---|
action |
UINT | 1 = start, 0 = cancel |
$O;SWSCAL#LEN;<status>,<air>,<water>\r
| Field | Type | Description |
|---|---|---|
status |
UINT | 0 = pending / in progress, 1 = completed OK, 2 = failed/cancelled |
air |
UINT | Air baseline ADC (0-16383). 0 if not yet sampled. |
water |
UINT | Water baseline ADC (0-16383). 0 if not yet sampled. |
Same envelope, with status=1 and final air/water values.
-
PARAM_KEY_UNRECOGNISED(6) — build hasENABLE_SWS_ANALOG=0(LoRa builds typically) -
MISSING_ARGUMENT(3) — no action argument
- Calling
SWSCAL,1automatically stops any runningSWSTSTtest mode first. - If BLE flaps mid-calibration, the async response is routed through whichever channel is current when calibration completes (BLE or USB) — the GUI should handle either.
- LED behavior during calibration is independent of
LED_MODE.
Read (or read + clear) the persistent SWS safety-mechanism counters introduced by the 2026-05 audit (R-MON-02). Each counter tracks how many times a specific recovery / safety path has fired since the last clear — used to detect sensor drift, biofouling, or hardware issues from field-recovered devices. Only on builds with ENABLE_SWS_ANALOG=1.
$SWSSTATS#001;0\r # Read counters
$SWSSTATS#001;1\r # Clear AND read (atomic)
| Arg | Type | Description |
|---|---|---|
action |
UINT | 0 = read-only, 1 = clear then read (returns post-clear values, all zeroes) |
$O;SWSSTATS#LEN;<stuck_rec>,<coh_recalib>,<dive_to>,<force_surf>,<spike_rej>,<peak_inc>,<saadc_retry>\r
| # | Field | Triggered by |
|---|---|---|
| 1 | stuck_rec |
Air-baseline collapse + surface state ⇒ proactive recovery (M6 in 13 — Underwater & Behavioral Modes § Safety mechanisms) |
| 2 | coh_recalib |
Coherence recalibration after baseline drift |
| 3 | dive_to |
UW_MAX_DIVE_TIME exceeded (water baseline recalibrated up) |
| 4 | force_surf |
Cascade level 3 fired — surface forced after 3 consecutive UW_MAX_DIVE_TIME events |
| 5 | spike_rej |
Single-sample spike rejection |
| 6 | peak_inc |
Peak ADC marked incoherent (decayed below water/2) and reset |
| 7 | saadc_retry |
SAADC re-init retry after NRFX_ERROR_INVALID_STATE
|
| Pattern | Likely cause |
|---|---|
dive_to > 0 |
Sensor stuck UW longer than UW_MAX_DIVE_TIME — likely sensor drift, biofouling, or hyper-saline pocket. Investigate. |
force_surf > 0 |
Cascade level 3 fired — definite sensor anomaly. Check electrode physically. |
stuck_rec > 0 |
Dry-electrode death spiral detected and recovered. Possible water seal compromise. |
spike_rej > N/day |
Noisy environment (vibration, RF interference?). Not a defect by itself. |
saadc_retry > 0 |
SAADC silicon needing re-init. Below the M1 threshold = fine; if > 60 in a row, force-surface kicks in. |
-
PARAM_KEY_UNRECOGNISED(6) — build hasENABLE_SWS_ANALOG=0 -
MISSING_ARGUMENT(3) — no action argument
Counters live in SWSAnalogService static state, persisted to flash on save. Survive reboots. Use action=1 to reset (for tests or before a fresh deployment).
Query u-blox M10Q hardware ID and firmware version. Powers on GNSS automatically if not cached.
$GNSSI#000;\r
→ $O;GNSSI#02B;01A2B3C4D5,SPG 4.04 (7b202e),00190000\r
Response: unique_id, sw_version, hw_version.
Check AssistNow Offline almanac file status.
$GNSSA#000;\r
→ $O;GNSSA#00D;1,32768,35,28,0\r
Response: present, file_size, total_records, valid_records, stale.
Manual LoRa test transmission. Only on LORA_RAK3172=ON builds.
| Arg | Type | Description |
|---|---|---|
| size | UINT | Payload size in bytes |
$LORATX#001;8\r
→ $O;LORATX#000;\r
The tracker exposes 3 UART bridges that turn the USB CDC port into a transparent pipe to the target module. Used for direct configuration / debug / firmware update of the connected module.
Common requirements for all bridges:
- Tracker must be in
ConfigurationState(enter via reed switch 3s or BLE auto-enter). - Activation via DTE command
$<CMD>#001;1\r; deactivation via$<CMD>#001;0\ror by sending+++. - While a bridge is active, debug logs are automatically suppressed on USB CDC to prevent pollution of the passthrough stream. Logs resume when the bridge is stopped.
- All 3 bridges are auto-stopped when
ConfigurationStateexits (reed exit, BLE inactivity timeout, error). No[BRIDGE OFF]confirmation is sent in those cases — the GUI should handle silence with a re-handshake.
Exit sequence +++:
| Bridge | Exit format | Why |
|---|---|---|
| GNSSBR | Exactly 3 bytes +++ (or +++\r / +++\n) |
Byte-stream mode (UBX binary) |
| KIMBR | Line +++\r\n
|
Line-based AT framing |
| LORABR | Line +++\r\n
|
Line-based AT framing |
Confirmation from tracker: \r\n[BRIDGE OFF]\r\n.
Energises the GNSS power rail and parks the u-blox M10Q in UBX-RXM-PMREQ backup sleep (~15 µA) so the on-board V_BCKP coin-cell / supercap charging circuit can top up the cell without running a normal GNSS acquisition (~25 mA). When the session ends the rail is powered off; on the next normal power_on the M10 hits the BBR fast-path → faster TTFF.
Two ways to drive the mode:
- Manual: this command (one-shot, overrides any scheduled session in flight).
-
Periodic: the GPS service reads
GNSS_BCKP_CHARGE_INT/_DUR/_UW_ONLYand arms its own scheduler — no DTE command required.
$GNSSBCKP#003;<duration_s>\r
| Arg | Type | Range | Description |
|---|---|---|---|
duration_s |
UINT | 0–86400 | Session length in seconds. 0 = stop the currently active charge session immediately.
|
$O;GNSSBCKP#000;\r
Errors:
-
INCORRECT_DATA(2) — GPS device unavailable (M10 not detected at boot) -
MISSING_ARGUMENT(3) —duration_snot supplied -
VALUE_OUT_OF_RANGE(4) — outside0..86400
-
Refused while a GNSS acquisition is in progress — wait for the fix (or
PWRON 4to stop GNSS) before issuing. -
Calling
GNSSBCKP <new_dur>while already charging — extends/replaces the auto-exit timer; does not re-cold-boot the M10. -
A scheduled GNSS acquisition (
service_initiate) takes priority — if the GPS service decides to fire a fix during the session, the backup mode is aborted synchronously and the normal acquisition starts. -
Saltwater-switch surface event with
GNSS_BCKP_CHARGE_UW_ONLY=truealso aborts the session immediately so theGNSS_TRIGGER_ON_SURFACEDflow runs unimpeded.
$GNSSBCKP#003;600\r → charge for 10 minutes
$GNSSBCKP#001;0\r → stop now
USB-to-GNSS UART passthrough for u-blox M10Q configuration via u-center or manual AssistNow loading. Raw byte-stream — UBX binary and NMEA ASCII both supported.
- Module UART baudrate: forced to 9600 by tracker (u-center default)
- Framing: none, raw bytes bidirectional
- ISR buffer: 1024 bytes (handles bulky UBX dumps)
| Arg | Value | Description |
|---|---|---|
| action | 1 | Start bridge |
| action | 0 | Stop bridge |
$GNSSBR#001;1\r # Start bridge
→ $O;GNSSBR#000;\r
<UBX bytes / NMEA lines bidirectional>
+++ # Exit (3 raw bytes)
→ \r\n[BRIDGE OFF]\r\n
USB-to-KIM2 UART passthrough for direct CLS KIM2 AT command access. Only available on KIM builds (neither ARGOS_SMD=1 nor LORA_RAK3172=1).
- Module UART baudrate: BSP default (configured at build time)
-
Framing: line-based — the tracker appends
\r\nto each USB line before forwarding to KIM2, and forwards each KIM2 line back with CRLF restored - If the KIM2 is powered off at start, the tracker powers it on automatically (500 ms boot delay)
| Arg | Value | Description |
|---|---|---|
| action | 1 | Start bridge |
| action | 0 | Stop bridge |
$KIMBR#001;1\r # Start bridge
→ $O;KIMBR#000;\r
AT+ID=? # GUI sends this line (CRLF appended automatically)
+ID=123456 # KIM2 response
+OK # KIM2 OK
+++ # Exit (line with CRLF)
→ \r\n[BRIDGE OFF]\r\n
Common AT commands: AT+PING=?, AT+ID=?, AT+ADDR=?, AT+RCONF=<hex>, AT+SAVE_RCONF, AT+KMAC=1, AT+LPM=0x0F, AT+TX=<hex>.
Note: send() is rejected with KineisEventDeviceError while the bridge is active — stop the bridge before triggering a TX via $SATTX or normal service operation.
USB-to-RAK3172 UART passthrough for direct RUI3 AT command access. Only available on LoRa builds (LORA_RAK3172=1). Useful for manual module configuration, diagnostics, and firmware updates.
- Module UART baudrate: 115200 (RAK3172 default)
-
Framing: line-based — same as KIMBR, tracker appends
\r\nautomatically
| Arg | Value | Description |
|---|---|---|
| action | 1 | Start bridge |
| action | 0 | Stop bridge |
$LORABR#001;1\r # Start bridge
→ $O;LORABR#000;\r
AT+DEVEUI=? # Direct AT command to RAK3172
0011223344556677 # Response from RAK3172
+++ # Exit (line with CRLF)
→ \r\n[BRIDGE OFF]\r\n
Common RUI3 commands: AT+VER=?, AT+BAND=?, AT+DEVEUI=?, AT+JOIN=1:0:10:8. Async events +EVT:JOINED, +EVT:TX_DONE, +EVT:RX_... are forwarded to the GUI as they arrive.
Trigger a Continuous Wave (CW) RF emission on the satellite or LoRa module. Used for regulatory certification (FCC, CE, etc.), antenna tuning measurements, and end-of-line production tests.
Module support:
| Build | Behavior |
|---|---|
ARGOS_SMD=1 |
Forwards to SMD cw_start() / cw_stop() STM32WL commands |
LORA_RAK3172=1 |
Forwards to RAK3172 cw_start() / cw_stop() AT commands (auto-wakes module if powered off) |
| KIM2 build (no SMD, no LoRa) | Returns status=0, info="CW not supported on this module"
|
$COMCW#001;0\r # Stop CW emission
$COMCW#011;1,401650000,22,30\r # Start CW: 401.65 MHz, 22 dBm, 30 s
| Arg | Type | Range | Required | Description |
|---|---|---|---|---|
mode |
UINT | 0 or 1 | yes | 0 = stop, 1 = start |
freq_hz |
UINT | module-specific | yes (mode=1) | Carrier frequency in Hz. SMD: ~401.6 MHz Argos band. LoRa: 863-928 MHz band-dependent. |
power_dbm |
UINT | 0-30 | yes (mode=1) | TX power in dBm. SMD typical 22 dBm at antenna. LoRa max 14 dBm in EU868. |
duration_s |
UINT | 0-3600 | optional | Max emission duration in seconds. 0 = no auto-stop, must call mode=0 to stop. Safe default: 30-60 s. |
$O;COMCW#LEN;<error_code>,<status>,<info>\r
| Field | Type | Description |
|---|---|---|
error_code |
UINT | Always 0 (frame-level OK). Real status is in next field. |
status |
UINT | 0 = success, 1 = failure |
info |
TEXT | Human-readable status: "CW start OK", "CW stop OK", "CW start failed", "CW not supported on this module", "SMD not available", "LoRa not available"
|
-
MISSING_ARGUMENT(3) —modemissing, ormode=1andfreq_hz/power_dbmmissing - Status field = 1 if module rejects (out-of-band frequency, hardware fault, module not detected)
- CW emission is illegal outside test environments. Only use in screened RF chambers or with regulator authorization.
- Always set a
duration_s≤ 60 s for protection — a stuck-on CW emission drains the battery in minutes and may violate spectrum rules. - After successful
cw_start, the module is in a non-normal state.mode=0(stop) must be issued before normal TX can resume. A reboot also recovers. - For LoRa:
cw_stopresets the RAK3172 module (clean state restore).
SMD certification (~60 s burst at 401.65 MHz, 22 dBm):
$COMCW#011;1,401650000,22,60\r
→ $O;COMCW#011;0,0,CW start OK
... (60 s emission, auto-stop) ...
Manual start/stop:
$COMCW#015;1,401650000,22,0\r # Start, no auto-stop
→ $O;COMCW#011;0,0,CW start OK
... (measurement) ...
$COMCW#001;0\r # Stop
→ $O;COMCW#012;0,0,CW stop OK
LoRa CW test (EU868 channel, 14 dBm):
$COMCW#011;1,868100000,14,30\r
→ $O;COMCW#011;0,0,CW start OK
For the complete table of all configurable parameters (keys, types, ranges, defaults, and detailed descriptions), see Parameters Definition.