mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2026-08-19 06:03:59 +00:00
cf44076a34
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.
200 lines
5.2 KiB
C++
200 lines
5.2 KiB
C++
#ifndef __PROC_FLEX_H__
|
|
#define __PROC_FLEX_H__
|
|
|
|
#include "baseband_processor.hpp"
|
|
#include "baseband_thread.hpp"
|
|
#include "dsp_decimate.hpp"
|
|
#include "dsp_demodulate.hpp"
|
|
#include "message.hpp"
|
|
#include "flex_defs.hpp"
|
|
#include "pocsag.hpp" // For EccContainer
|
|
|
|
#include <cstdint>
|
|
#include <array>
|
|
|
|
namespace flex {
|
|
|
|
enum class PageType {
|
|
SECURE,
|
|
SHORT_INSTRUCTION,
|
|
TONE,
|
|
STANDARD_NUMERIC,
|
|
SPECIAL_NUMERIC,
|
|
ALPHANUMERIC,
|
|
BINARY,
|
|
NUMBERED_NUMERIC
|
|
};
|
|
|
|
enum class State {
|
|
SYNC1,
|
|
FIW,
|
|
SYNC2,
|
|
DATA
|
|
};
|
|
|
|
struct FlexDemodParams {
|
|
unsigned int sample_freq = 24000;
|
|
double sample_last = 0.0;
|
|
int locked = 0;
|
|
int phase = 0;
|
|
unsigned int sample_count = 0;
|
|
unsigned int symbol_count = 0;
|
|
double envelope_sum = 0.0;
|
|
int envelope_count = 0;
|
|
uint64_t lock_buf = 0;
|
|
int symcount[4] = {0};
|
|
int timeout = 0;
|
|
int nonconsec = 0;
|
|
unsigned int baud = 1600;
|
|
};
|
|
|
|
struct FlexGroupHandler {
|
|
int64_t GroupCodes[17][100]; // Reduced size from 1000 to save RAM
|
|
int GroupCycle[17];
|
|
int GroupFrame[17];
|
|
};
|
|
|
|
struct FlexModulation {
|
|
double symbol_rate = 0.0;
|
|
double envelope = 0.0;
|
|
double zero = 0.0;
|
|
};
|
|
|
|
struct FlexStateInfo {
|
|
unsigned int sync2_count = 0;
|
|
unsigned int data_count = 0;
|
|
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 {
|
|
unsigned int sync = 0;
|
|
unsigned int baud = 0;
|
|
unsigned int levels = 0;
|
|
unsigned int polarity = 0;
|
|
uint64_t syncbuf = 0;
|
|
};
|
|
|
|
struct FlexFIW {
|
|
uint32_t rawdata = 0;
|
|
unsigned int checksum = 0;
|
|
unsigned int cycleno = 0;
|
|
unsigned int frameno = 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 {
|
|
uint32_t buf[88] = {0};
|
|
int idle_count = 0;
|
|
};
|
|
|
|
struct FlexData {
|
|
int phase_toggle = 0;
|
|
unsigned int data_bit_counter = 0;
|
|
FlexPhase PhaseA;
|
|
FlexPhase PhaseB;
|
|
FlexPhase PhaseC;
|
|
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
|
|
|
|
class FlexProcessor : public BasebandProcessor {
|
|
public:
|
|
void execute(const buffer_c8_t& buffer) override;
|
|
void on_message(const Message* const message) override;
|
|
|
|
private:
|
|
bool configured{false};
|
|
|
|
// DSP components
|
|
// 3.072MHz -> 24kHz (Decim 128)
|
|
// decim_0: 8, decim_1: 8, channel: 2. Total 128.
|
|
dsp::decimate::FIRC8xR16x24FS4Decim8 decim_0_iq{};
|
|
dsp::decimate::FIRC16xR16x32Decim8 decim_1_iq{};
|
|
dsp::decimate::FIRAndDecimateComplex channel_filter{};
|
|
dsp::demodulate::FM demod{};
|
|
|
|
// Buffers
|
|
std::array<complex16_t, 256> dst{};
|
|
const buffer_c16_t dst_buffer{dst.data(), dst.size()};
|
|
|
|
std::array<float, 16> audio{};
|
|
const buffer_f32_t audio_buffer{audio.data(), audio.size()};
|
|
|
|
// Flex State
|
|
flex::FlexDemodParams demodulator{};
|
|
flex::FlexModulation modulation{};
|
|
flex::FlexStateInfo state{};
|
|
flex::FlexSync sync{};
|
|
flex::FlexFIW fiw{};
|
|
flex::FlexData data{};
|
|
flex::FlexDecode decode{};
|
|
flex::FlexGroupHandler group_handler{};
|
|
|
|
pocsag::EccContainer ecc{};
|
|
|
|
// Methods
|
|
void configure();
|
|
void process_audio(const buffer_f32_t& audio);
|
|
|
|
// Internal Flex logic
|
|
int build_symbol(double sample);
|
|
void flex_demodulate(double sample);
|
|
void flex_sym(unsigned char sym);
|
|
unsigned int flex_sync_check(uint64_t buf);
|
|
unsigned int flex_sync(unsigned char sym);
|
|
void decode_mode(unsigned int sync_code);
|
|
void read_2fsk(unsigned int sym, uint32_t* dat); // Changed to uint32_t*
|
|
int decode_fiw();
|
|
int read_data(unsigned char sym);
|
|
void decode_data();
|
|
void decode_phase(char PhaseNo);
|
|
int bch_fix_errors(uint32_t* data_to_fix);
|
|
|
|
// Parsing
|
|
void parse_capcode(uint32_t aw1);
|
|
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);
|
|
|
|
void send_packet(const flex::FlexPacket& packet);
|
|
void send_stats();
|
|
void send_debug(const char* text, uint32_t v1, uint32_t v2);
|
|
|
|
// Threads
|
|
BasebandThread baseband_thread{3072000, this, baseband::Direction::Receive};
|
|
};
|
|
|
|
#endif /*__PROC_FLEX_H__*/
|