gr-rylr998/grc/rylr998_phy_decode.block.yml
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

84 lines
1.9 KiB
YAML

id: rylr998_phy_decode
label: RYLR998 PHY Decoder
category: '[RYLR998]/PHY'
flags: [python, cpp]
documentation: |-
LoRa PHY layer decoder.
Complete receive chain: Gray decode → Deinterleave → Hamming FEC → Dewhiten
Decodes CSS-demodulated symbol bins into payload bytes using the
gr-lora_sdr compatible signal chain.
RX chain order:
1. Apply correction: (bin - cfo_bin - 1) % N
2. Reduced rate (header): divide by 4, use SF-2 bits
3. Gray map: x ^ (x >> 1) (counterintuitive but correct!)
4. Deinterleave
5. Hamming FEC decode
6. Dewhiten payload
7. CRC check
Input: Aligned data symbol bins (from Frame Sync)
Output: Decoded payload bytes
templates:
imports: from rylr998 import phy_decode
make: rylr998.phy_decode(sf=${sf}, cr=${cr}, has_crc=${has_crc}, ldro=${ldro}, implicit_header=${implicit_header}, payload_len=${payload_len})
parameters:
- id: sf
label: Spreading Factor
dtype: int
default: 9
options: [7, 8, 9, 10, 11, 12]
option_labels: ['SF7', 'SF8', 'SF9', 'SF10', 'SF11', 'SF12']
- id: cr
label: Coding Rate
dtype: int
default: 1
options: [1, 2, 3, 4]
option_labels: ['4/5', '4/6', '4/7', '4/8']
- id: has_crc
label: CRC Enabled
dtype: bool
default: 'True'
options: ['True', 'False']
- id: ldro
label: Low Data Rate Opt
dtype: bool
default: 'False'
options: ['True', 'False']
- id: implicit_header
label: Implicit Header
dtype: bool
default: 'False'
options: ['True', 'False']
- id: payload_len
label: Payload Length (Implicit)
dtype: int
default: 0
hide: ${ 'all' if not implicit_header else 'none' }
inputs:
- label: symbols
domain: message
dtype: int
outputs:
- label: payload
domain: message
dtype: byte
- label: frame_info
domain: message
optional: true
file_format: 1