Forráskód Böngészése

fix(kiss): periodic noise floor calibration and AGC reset

- Trigger noise floor calibration every 2s and AGC reset every 30s in main loop.
- Reorder loop to match Dispatcher: calibrate + radio.loop() before AGC reset
  and recvRaw() so RSSI is never sampled right after startReceive().
- Update protocol doc with calibration intervals and typical noise floor range.
- Variant platformio.ini updates (heltec_v3, rak4631).
agessaman 6 hónapja
szülő
commit
0fb570338f

+ 16 - 4
docs/kiss_modem_protocol.md

@@ -28,6 +28,8 @@ Maximum unescaped frame size: 512 bytes.
 
 ## Commands
 
+Command and response codes below are taken from `examples/kiss_modem/KissModem.h` and the switch in `KissModem::processFrame()`.
+
 ### Request Commands (Host → Modem)
 
 | Command | Value | Data |
@@ -43,10 +45,10 @@ Maximum unescaped frame size: 512 bytes.
 | `CMD_HASH` | `0x08` | Data to hash |
 | `CMD_SET_RADIO` | `0x09` | Freq (4) + BW (4) + SF (1) + CR (1) |
 | `CMD_SET_TX_POWER` | `0x0A` | Power dBm (1) |
-| `CMD_SET_SYNC_WORD` | `0x0B` | Sync word (1) |
+| *reserved* | `0x0B` | *(not implemented)* |
 | `CMD_GET_RADIO` | `0x0C` | - |
 | `CMD_GET_TX_POWER` | `0x0D` | - |
-| `CMD_GET_SYNC_WORD` | `0x0E` | - |
+| *reserved* | `0x0E` | *(not implemented)* |
 | `CMD_GET_VERSION` | `0x0F` | - |
 | `CMD_GET_CURRENT_RSSI` | `0x10` | - |
 | `CMD_IS_CHANNEL_BUSY` | `0x11` | - |
@@ -73,7 +75,7 @@ Maximum unescaped frame size: 512 bytes.
 | `RESP_OK` | `0x29` | - |
 | `RESP_RADIO` | `0x2A` | Freq (4) + BW (4) + SF (1) + CR (1) |
 | `RESP_TX_POWER` | `0x2B` | Power dBm (1) |
-| `RESP_SYNC_WORD` | `0x2C` | Sync word (1) |
+| *reserved* | `0x2C` | *(not implemented)* |
 | `RESP_VERSION` | `0x2D` | Version (1) + Reserved (1) |
 | `RESP_ERROR` | `0x2E` | Error code (1) |
 | `RESP_TX_DONE` | `0x2F` | Result (1): 0x00=failed, 0x01=success |
@@ -119,9 +121,19 @@ All values little-endian.
 | RSSI | 1 byte | Signal strength dBm, signed |
 | Packet | variable | Raw MeshCore packet |
 
+### Noise Floor (RESP_NOISE_FLOOR)
+
+Response to `CMD_GET_NOISE_FLOOR` (0x13). Little-endian.
+
+| Field        | Size | Description                    |
+|--------------|------|--------------------------------|
+| Noise floor  | 2    | int16_t, dBm (signed), e.g. -120 |
+
+The modem recalibrates the noise floor periodically (every 2 s) from RX samples when idle. The receiver AGC is also reset periodically (every 30 s) so RSSI and noise floor do not drift to the minimum (-120). Typical range after calibration is about -120 to -90 dBm. Values may be 0 or briefly stale until the radio has been in receive mode long enough to collect 64 samples.
+
 ### Stats (RESP_STATS)
 
-All values little-endian.
+Response to `CMD_GET_STATS` (0x14). All values little-endian.
 
 | Field | Size | Description |
 |-------|------|-------------|

+ 19 - 4
examples/kiss_modem/main.cpp

@@ -12,9 +12,14 @@
   #include <SPIFFS.h>
 #endif
 
+#define NOISE_FLOOR_CALIB_INTERVAL_MS  2000   // match Dispatcher default
+#define AGC_RESET_INTERVAL_MS         30000  // periodic RX restart so AGC doesn't drift (repeater uses same via prefs)
+
 StdRNG rng;
 mesh::LocalIdentity identity;
 KissModem* modem;
+static uint32_t next_noise_floor_calib_ms = 0;
+static uint32_t next_agc_reset_ms = 0;
 
 void halt() {
   while (1) ;
@@ -94,7 +99,16 @@ void loop() {
 
   uint8_t packet[KISS_MAX_PACKET_SIZE];
   uint16_t len;
-  
+
+  // Match Dispatcher order: noise floor calib + loop() first, so we never sample RSSI in the same
+  // iteration as startReceive() (AGC reset -> recvRaw below). Sampling right after startReceive()
+  // can yield settling/cold RSSI and drive the floor toward -120.
+  if ((uint32_t)(millis() - next_noise_floor_calib_ms) >= NOISE_FLOOR_CALIB_INTERVAL_MS) {
+    radio_driver.triggerNoiseFloorCalibrate(0);   // 0 = no interference threshold (KISS has no prefs)
+    next_noise_floor_calib_ms = millis();
+  }
+  radio_driver.loop();
+
   if (modem->getPacketToSend(packet, &len)) {
     radio_driver.startSendRaw(packet, len);
     while (!radio_driver.isSendComplete()) {
@@ -104,14 +118,15 @@ void loop() {
     modem->onTxComplete(true);
   }
 
+  if ((uint32_t)(millis() - next_agc_reset_ms) >= AGC_RESET_INTERVAL_MS) {
+    radio_driver.resetAGC();   // next recvRaw() will startReceive() and reset AGC so RSSI/noise floor don't stick at -120
+    next_agc_reset_ms = millis();
+  }
   uint8_t rx_buf[256];
   int rx_len = radio_driver.recvRaw(rx_buf, sizeof(rx_buf));
-  
   if (rx_len > 0) {
     int8_t snr = (int8_t)(radio_driver.getLastSNR() * 4);
     int8_t rssi = (int8_t)radio_driver.getLastRSSI();
     modem->onPacketReceived(snr, rssi, rx_buf, rx_len);
   }
-
-  radio_driver.loop();
 }

+ 9 - 0
variants/heltec_v3/platformio.ini

@@ -367,3 +367,12 @@ build_src_filter = ${Heltec_lora32_v3.build_src_filter}
 lib_deps =
   ${Heltec_lora32_v3.lib_deps}
   ${esp32_ota.lib_deps}
+
+[env:Heltec_v3_kiss_modem]
+extends = Heltec_lora32_v3
+build_flags =
+  ${Heltec_lora32_v3.build_flags}
+build_src_filter = ${Heltec_lora32_v3.build_src_filter}
+  +<../examples/kiss_modem/>
+lib_deps =
+  ${Heltec_lora32_v3.lib_deps}

+ 10 - 1
variants/rak4631/platformio.ini

@@ -183,4 +183,13 @@ build_flags =
   -D MESH_DEBUG=1
 build_src_filter = ${rak4631.build_src_filter}
   +<helpers/ui/SSD1306Display.cpp>
-  +<../examples/simple_sensor>
+  +<../examples/simple_sensor>
+
+[env:RAK_4631_kiss_modem]
+extends = rak4631
+build_flags =
+  ${rak4631.build_flags}
+build_src_filter = ${rak4631.build_src_filter}
+  +<../examples/kiss_modem/>
+lib_deps =
+  ${rak4631.lib_deps}