FLEX RX: comprehensive decoder rewrite (#3131)

Baseband (proc_flex.cpp):
- Fix numeric vector field width (3-bit n+1 for types 3,4,7)
- Fix capcode range classification for long address components
- Add long address decode (Set 1-2, 1-3/1-4, 2-3)
- Add vector checksum validation (4-bit nibble sum)
- Add tone-only boundary detection via vector pre-scan
- Add idle phase detection (skip all-zeros/all-ones before BCH)
- Skip spurious TON for capcode 1 (BCH-corrected idle artifact)
- Add BIW parsing: SSID1/SSID2, DATE, TIME, TZ, SYSMSG, CHAN
- Add alpha fragment flags: frag, more_frag, seq, new, maildrop, sig
- Add secure message enc= field (alpha/binary/separate)
- Add numbered numeric flags: seq, new, fmt
- Add HEX/Binary header decode: block_bits, new, maildrop, rtl
- Add short instruction decode: temp group slot/target, sys events
- Add short message (SMSG) decode: tone/numeric/source/numbered
- Add group/temp-group/priority flags per address
- Add S2 C-pattern detection with ±1 symbol boundary correction
- Extract FIW roaming, repeat, traffic fields
- Replace snprintf with lightweight str_* helpers (no heap/_sbrk)
- Mark uncorrectable BCH words as ? instead of aborting phase
- ETX/NUL handling: trim trailing padding, show mid-message as ?

App (ui_flex_rx.cpp):
- Add status bar: cycle/frame, bitrate, polarity, time, timezone
- Add network info bar: LID, CZ, CC, roaming flag
- Pipe-delimited serial output for all message types
- BIW events to serial and status bar (not console)
- Human-readable console: +GRP for temp group, G/TG/P flags
- USB serial via UsbSerialAsyncmsg

Packet (flex_defs.hpp):
- uint64_t capcode (long address support)
- 256-byte message buffer
- Fragment flags, BIW raw values, address type, group/priority

Known limitation: phase label unreliable on multi-phase modes
(3200/2FSK, 6400/4FSK). Data always decodes correctly.
This commit is contained in:
VasylSamoilov
2026-04-10 09:37:38 +03:00
committed by GitHub
parent dd006b4830
commit cf44076a34
5 changed files with 1035 additions and 81 deletions
+24 -2
View File
@@ -66,6 +66,11 @@ struct FlexStateInfo {
unsigned int fiwcount = 0;
State Current = State::SYNC1;
State Previous = State::SYNC1;
// S2 C-pattern detection
uint16_t sync2_shiftreg = 0; // 16-bit shift register for C match
int sync2_c_pos = -1; // symbol position where C was found (-1=not found)
int sync2_cinv_pos = -1; // symbol position where inv.C was found
};
struct FlexSync {
@@ -81,7 +86,9 @@ struct FlexFIW {
unsigned int checksum = 0;
unsigned int cycleno = 0;
unsigned int frameno = 0;
unsigned int fix3 = 0;
unsigned int roaming = 0; // bit 15: n (1=roaming provided)
unsigned int repeat = 0; // bit 16: r (1=multiple transmission)
unsigned int traffic = 0; // bits 17-20: t3-t0
};
struct FlexPhase {
@@ -98,10 +105,25 @@ struct FlexData {
FlexPhase PhaseD;
};
enum class AddrType : uint8_t {
SHORT, // normal individual
LONG, // 9-10 digit
TEMPORARY, // 0x1F7800-0F (16 group slots)
OPERATOR, // 0x1F7810-1F (system messages)
NETWORK, // 0x1F6800-77FF (NID)
INFO_SVC, // 0x1F2800-67FF (under study)
RESERVED, // reserved ranges
UNKNOWN
};
struct FlexDecode {
PageType type = PageType::ALPHANUMERIC;
int long_address = 0;
int64_t capcode = 0;
AddrType addr_type = AddrType::SHORT;
int is_group = 0;
int is_temp_group = 0;
int is_priority = 0;
};
} // namespace flex
@@ -161,7 +183,7 @@ class FlexProcessor : public BasebandProcessor {
// Parsing
void parse_capcode(uint32_t aw1);
void parse_alphanumeric(uint32_t* phaseptr, char PhaseNo, int mw1, int mw2, int flex_groupmessage);
void parse_alphanumeric(uint32_t* phaseptr, const uint8_t* word_bad, char PhaseNo, int mw1, int mw2, int flex_groupmessage);
void parse_numeric(uint32_t* phaseptr, char PhaseNo, int j);
void parse_tone_only(uint32_t* phaseptr, char PhaseNo, int j);
void parse_unknown(uint32_t* phaseptr, char PhaseNo, int mw1, int mw2);