gr-rylr998/docs/NETWORKID_MAPPING.md
Ryan Malloy c839d225a8 Initial release: complete LoRa TX/RX for RYLR998 modems
GNU Radio Out-of-Tree module providing:
- Complete TX chain: PHYEncode → FrameGen → CSSMod
- Complete RX chain: CSSDemod → FrameSync → PHYDecode
- NETWORKID extraction/encoding (0-255 range)
- All SF (7-12) and CR (4/5-4/8) combinations
- Loopback tested with 24/24 configurations passing

Key features:
- Fractional SFD (2.25 downchirp) handling
- Gray encode/decode with proper inverse operations
- gr-lora_sdr compatible decode modes
- GRC block definitions and example flowgraphs
- Comprehensive documentation

Discovered RYLR998 sync word mapping:
  sync_bin_1 = (NETWORKID >> 4) * 8
  sync_bin_2 = (NETWORKID & 0x0F) * 8
2026-02-05 13:38:07 -07:00

83 lines
2.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# RYLR998 NETWORKID ↔ LoRa Sync Word Mapping
## Discovery
Through SDR captures and analysis, we discovered that the RYLR998 module's NETWORKID (0-255) maps directly to the LoRa sync word byte using a simple nibble-to-bin transformation.
## The Mapping
```
Sync Word Byte: 0xHH where H = high nibble, L = low nibble
CSS Symbol 1 (sync_delta_1) = H × 8 = (NID >> 4) × 8
CSS Symbol 2 (sync_delta_2) = L × 8 = (NID & 0x0F) × 8
```
The factor of 8 is a **fixed constant** used by RYLR998 (verified through SDR captures). This differs from standard LoRa which would use `N/16` scaling.
## Verification
| NETWORKID | Hex | High Nibble | Low Nibble | Sync Bin 1 | Sync Bin 2 | Verified |
|-----------|------|-------------|------------|------------|------------|----------|
| 3 | 0x03 | 0 | 3 | 0 | 24 | ✓ |
| 5 | 0x05 | 0 | 5 | 0 | 40 | ✓ |
| 17 | 0x11 | 1 | 1 | 8 | 8 | ✓ |
| 18 | 0x12 | 1 | 2 | 8 | 16 | ✓ |
| 52 | 0x34 | 3 | 4 | 24 | 32 | (LoRaWAN)|
## Standard LoRa Sync Words
| Name | Sync Byte | NETWORKID | Sync Bins |
|---------------|-----------|-----------|-------------|
| Private | 0x12 | 18 | [8, 16] |
| LoRaWAN Public| 0x34 | 52 | [24, 32] |
## Code Implementation
### Python
```python
def networkid_to_sync_word(nid: int) -> tuple[int, int]:
"""Convert NETWORKID to sync word symbol deltas."""
high_nibble = (nid >> 4) & 0x0F
low_nibble = nid & 0x0F
return (high_nibble * 8, low_nibble * 8)
def sync_word_to_networkid(deltas: tuple[int, int]) -> int:
"""Convert sync word deltas back to NETWORKID."""
high_nibble = deltas[0] // 8
low_nibble = deltas[1] // 8
return (high_nibble << 4) | low_nibble
```
### Full Range Table
```
NID=0 (0x00) → sync=[ 0, 0]
NID=1 (0x01) → sync=[ 0, 8]
NID=2 (0x02) → sync=[ 0, 16]
...
NID=16 (0x10) → sync=[ 8, 0]
NID=17 (0x11) → sync=[ 8, 8]
NID=18 (0x12) → sync=[ 8, 16]
...
NID=255 (0xFF) → sync=[120, 120]
```
## Why This Matters
1. **Interoperability**: You can decode RYLR998 traffic with standard LoRa hardware by knowing the sync word
2. **Filtering**: Filter frames by NETWORKID in software without full decode
3. **Testing**: Generate RYLR998-compatible frames from any SDR
## SDR Capture Notes
When capturing RYLR998 frames:
1. The preamble consists of 8+ upchirps at bin 0
2. Sync word is 2 upchirps with bins = nibble × (N/16)
3. SFD is 2.25 downchirps
4. Data follows with the encoded payload
The sync word symbols are measured relative to the preamble bin (which represents the carrier frequency offset).