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