Skip to content
Prev Previous commit
Fix SX1262 RX: correct GET_RX_BUFFER_STATUS byte offsets
The SX1262 echoes the status byte twice in the GET_RX_BUFFER_STATUS
response (bytes [0] and [1] are both status), so RxPayloadLength and
RxStartBufferPointer are at bytes [2] and [3], not [1] and [2].
Using the wrong offsets caused nb=212 (status byte value) instead of
the actual packet length (~47 bytes), resulting in garbage-padded RX.

Also separate TX/RX buffer base addresses (TX=0x00, RX=0x80) to
prevent any overlap between transmitted and received data.

Tested on MeshAdv-Pi Hat (E22-400M30S, SX1262, 433 MHz):
- TX confirmed via APRS-IS (heard by K6ATV-31)
- RX confirmed decoding DL5TKL T-Echo beacons cleanly

Updated LoRa-APRS.md: corrected MeshAdv frequency, added TX/RX
tested status to hardware table, added note on SX1262 status byte
echo quirk for future porters.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
  • Loading branch information
radiohound and claude committed Mar 31, 2026
commit 56b7d1eddbbfb652749433d53c2d39b339195137
28 changes: 18 additions & 10 deletions doc/LoRa-APRS.md
Original file line number Diff line number Diff line change
Expand Up @@ -227,16 +227,24 @@ Profiles are defined in `hardware_profiles.yaml` (Python bridge) or selected
with `LORAHW` in `direwolf.conf` (native SPI driver). Both use the same
profile names.

| Profile name | Module | Chip | Frequency |
|---|---|---|---|
| `lorapi_rfm95w` | Digital Concepts LoRa-Pi (RFM95W) | SX1276 | 868/915 MHz |
| `lorapi_rfm98w` | Digital Concepts LoRa-Pi (RFM98W) | SX1278 | 433 MHz |
| `generic_sx1276` | Generic SX1276/SX1278 breakout | SX1276 | varies |
| `meshadv` | MeshAdv-Pi Hat | SX1262 | 900 MHz |
| `e22_900m30s` | Ebyte E22-900M30S | SX1262 | 868/915 MHz |
| `e22_400m30s` | Ebyte E22-400M30S | SX1268 | 433/470 MHz |
| `ebyte_e22` | Ebyte E22 generic | SX1262 | varies |
| `ttgo_uart` | TTGO/Heltec over USB serial | external | varies |
| Profile name | Module | Chip | Frequency | TX tested | RX tested |
|---|---|---|---|---|---|
| `lorapi_rfm95w` | Digital Concepts LoRa-Pi (RFM95W) | SX1276 | 868/915 MHz | | |
| `lorapi_rfm98w` | Digital Concepts LoRa-Pi (RFM98W) | SX1278 | 433 MHz | yes | yes |
| `generic_sx1276` | Generic SX1276/SX1278 breakout | SX1276 | varies | | |
| `meshadv` | MeshAdv-Pi Hat (E22-400M30S, 1W PA) | SX1262 | 433 MHz | yes | yes |
| `e22_900m30s` | Ebyte E22-900M30S | SX1262 | 868/915 MHz | | |
| `e22_400m30s` | Ebyte E22-400M30S | SX1262 | 433/470 MHz | | |
| `ebyte_e22` | Ebyte E22 generic | SX1262 | varies | | |
| `ttgo_uart` | TTGO/Heltec over USB serial | external | varies | | |

> **SX1262 note:** The SX1262 GET_RX_BUFFER_STATUS command echoes the status
> byte twice before returning payload length and buffer pointer. The native
> driver (`loraspi.c`) accounts for this — bytes `[2]` and `[3]` of the
> response are the actual `RxPayloadLength` and `RxStartBufferPointer`,
> not `[1]` and `[2]` as implied by some versions of the datasheet. If
> you are porting this code to another platform, watch out for this or you
> will receive garbled, over-length packets.

To add a new profile for the **Python bridge**, copy an existing entry in
`hardware_profiles.yaml` and adjust the SPI bus, GPIO pins, and chip type.
Expand Down
11 changes: 6 additions & 5 deletions src/loraspi.c
Original file line number Diff line number Diff line change
Expand Up @@ -748,8 +748,8 @@ static bool sx1262_init (lora_chan_t *lc) {
sx1262_write_reg(lc, 0x0740, sw_hi);
sx1262_write_reg(lc, 0x0741, sw_lo);

/* Buffer base addresses: TX=0x00, RX=0x00 */
uint8_t buf_base[3] = { SX1262_CMD_SET_BUFFER_BASE_ADDR, 0x00, 0x00 };
/* Buffer base addresses: TX=0x00, RX=0x80 (separate halves to prevent overlap) */
uint8_t buf_base[3] = { SX1262_CMD_SET_BUFFER_BASE_ADDR, 0x00, 0x80 };
uint8_t buf_rx[3];
sx1262_cmd(lc, buf_base, buf_rx, 3);

Expand Down Expand Up @@ -785,9 +785,10 @@ static int sx1262_receive (lora_chan_t *lc, uint8_t *buf, int maxlen,
uint8_t get_buf[4] = { SX1262_CMD_GET_RX_BUFFER_STATUS, 0, 0, 0 };
uint8_t buf_rx[4];
sx1262_cmd(lc, get_buf, buf_rx, 4);
/* buf_rx[0]=status, [1]=payloadLength, [2]=rxStartBufferPointer */
int nb = buf_rx[1];
int offset = buf_rx[2];
/* SX1262 echoes status on both byte[0] and byte[1]; data starts at byte[2] */
/* buf_rx[0]=status, [1]=status(echo), [2]=payloadLength, [3]=rxStartBufferPointer */
int nb = buf_rx[2];
int offset = buf_rx[3];
if (nb <= 0 || nb > maxlen) return -1;

/* Read buffer (fixed max 256 bytes payload) */
Expand Down