UA1ZBE Custom Firmware v1.0
Features: - VFO mode with direct frequency input - POCSAG decoder (512/1200 baud) with BCH(31,21) correction - Full-screen Spectrum analyzer - FM Radio receiver - RSSI signal indicator overlay - Custom boot splash (UA1ZBE / POCSAG pager / build date) Architecture: - app/mode.c — mode dispatcher (VFO/POCSAG/Spectrum/FM) - app/boot_splash.c — 2-second boot splash - app/pocsag/ — POCSAG decoder + BCH correction - app/display_rssi.c — RSSI indicator - main.c — entry point with custom init - syscalls.c — bare-metal _sbrk stub Build: arm-none-eabi-gcc -Os -flto -Wall -Werror -Wextra Size: 57.9KB Flash / 3.6KB RAM Controls: - 0-9: Direct frequency input (VFO) - SK2: POCSAG mode - SK1: Spectrum analyzer - 0: FM Radio - EXIT: Return to VFO - F/*: Toggle 512/1200 baud (in POCSAG)
This commit is contained in:
150
app/pocsag/pocsag.h
Normal file
150
app/pocsag/pocsag.h
Normal file
@@ -0,0 +1,150 @@
|
||||
/* UA1ZBE Custom Firmware - POCSAG Decoder
|
||||
*
|
||||
* Decodes POCSAG paging signals from FM discriminator output.
|
||||
* Supports 512 and 1200 baud rates with dynamic switching.
|
||||
*
|
||||
* POCSAG Protocol:
|
||||
* - Preamble: 0xAAAAAAAB (at least 576 bits of alternating 1010... ending with 1)
|
||||
* - Sync word: 0x7CD21538
|
||||
* - Data words: 32-bit (21 data + 10 BCH + 1 parity)
|
||||
* - BCH(31,21) code, corrects up to 2 errors per word
|
||||
*
|
||||
* Architecture:
|
||||
* - Samples audio from BK4819 discriminator (REG_69 AF output or FSK FIFO)
|
||||
* - Zero-crossing detection for bit slicing
|
||||
* - State machine: IDLE -> PREAMBLE -> SYNC -> DATA
|
||||
* - Ring buffer for decoded messages
|
||||
* - Zero malloc — all static allocation
|
||||
*/
|
||||
|
||||
#ifndef APP_POCSAG_POCSAG_H
|
||||
#define APP_POCSAG_POCSAG_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* POCSAG baud rates */
|
||||
#define POCSAG_BAUD_512 512
|
||||
#define POCSAG_BAUD_1200 1200
|
||||
|
||||
/* Maximum message length in bytes (arbitrary, fits in static buffer) */
|
||||
#define POCSAG_MSG_MAX_LEN 64
|
||||
|
||||
/* Maximum messages in ring buffer */
|
||||
#define POCSAG_MSG_POOL_SIZE 8
|
||||
|
||||
/* Decoded message structure */
|
||||
typedef struct {
|
||||
uint32_t address; /* Address (21-bit frame address) */
|
||||
uint8_t func; /* Function code (2 bits) */
|
||||
char text[POCSAG_MSG_MAX_LEN]; /* Decoded text (alpha pager) */
|
||||
uint8_t text_len; /* Length of decoded text */
|
||||
bool is_alpha; /* true = alpha pager, false = numeric */
|
||||
uint32_t timestamp; /* System tick when received */
|
||||
} pocsag_msg_t;
|
||||
|
||||
/* Decoder state machine states */
|
||||
typedef enum {
|
||||
POCSAG_STATE_IDLE = 0,
|
||||
POCSAG_STATE_PREAMBLE,
|
||||
POCSAG_STATE_SYNC,
|
||||
POCSAG_STATE_DATA
|
||||
} pocsag_state_t;
|
||||
|
||||
/* Decoder context — all static, no malloc */
|
||||
typedef struct {
|
||||
/* Configuration */
|
||||
uint32_t baud_rate; /* Current baud rate: 512 or 1200 */
|
||||
|
||||
/* State machine */
|
||||
pocsag_state_t state;
|
||||
|
||||
/* Bit accumulation */
|
||||
uint32_t shift_reg; /* Shift register for incoming bits */
|
||||
uint8_t bit_count; /* Number of bits collected in shift_reg */
|
||||
uint8_t preamble_count; /* Consecutive alternating bits in preamble */
|
||||
|
||||
/* Sync detection */
|
||||
uint8_t sync_word_count; /* Number of sync words found in a row */
|
||||
|
||||
/* Word collection */
|
||||
uint8_t batch_count; /* Words in current batch (0-16) */
|
||||
uint8_t word_in_batch; /* Current word position in batch */
|
||||
|
||||
/* Message assembly */
|
||||
uint32_t current_address;
|
||||
uint8_t current_func;
|
||||
uint8_t msg_data[POCSAG_MSG_MAX_LEN];
|
||||
uint8_t msg_len;
|
||||
bool msg_is_alpha;
|
||||
|
||||
/* Ring buffer of decoded messages */
|
||||
pocsag_msg_t messages[POCSAG_MSG_POOL_SIZE];
|
||||
volatile uint8_t msg_read_idx;
|
||||
volatile uint8_t msg_write_idx;
|
||||
volatile uint8_t msg_count;
|
||||
|
||||
/* Statistics */
|
||||
uint32_t total_bits;
|
||||
uint32_t total_words;
|
||||
uint32_t corrected_errors;
|
||||
uint32_t uncorrectable_errors;
|
||||
|
||||
/* Flag for new message available */
|
||||
volatile bool msg_available;
|
||||
|
||||
/* Signal active flag */
|
||||
bool signal_detected;
|
||||
|
||||
} pocsag_decoder_t;
|
||||
|
||||
/* Global decoder instance */
|
||||
extern pocsag_decoder_t gPocsag;
|
||||
|
||||
/* === API === */
|
||||
|
||||
/* Initialize decoder, set baud rate */
|
||||
void POCSAG_Init(uint32_t baud_rate);
|
||||
|
||||
/* Switch baud rate dynamically (512 <-> 1200) */
|
||||
void POCSAG_SwitchBaud(uint32_t baud_rate);
|
||||
|
||||
/* Get current baud rate */
|
||||
uint32_t POCSAG_GetBaud(void);
|
||||
|
||||
/* Feed audio sample (12-bit ADC value from discriminator)
|
||||
* Call this from the 10ms timeslice or a dedicated sampling timer.
|
||||
* Returns true if a bit was detected. */
|
||||
bool POCSAG_FeedSample(uint16_t audio_sample);
|
||||
|
||||
/* Feed a single bit (after external bit-slicing) */
|
||||
void POCSAG_FeedBit(bool bit);
|
||||
|
||||
/* Check if a decoded message is available (non-blocking) */
|
||||
bool POCSAG_MessageAvailable(void);
|
||||
|
||||
/* Pop the next decoded message from the ring buffer */
|
||||
bool POCSAG_GetMessage(pocsag_msg_t *msg);
|
||||
|
||||
/* Get decoder state (for display) */
|
||||
pocsag_state_t POCSAG_GetState(void);
|
||||
|
||||
/* Get signal detection status */
|
||||
bool POCSAG_SignalDetected(void);
|
||||
|
||||
/* Reset decoder to idle state */
|
||||
void POCSAG_Reset(void);
|
||||
|
||||
/* Process decoder state machine (call from main loop) */
|
||||
void POCSAG_Process(void);
|
||||
|
||||
/* Configure BK4819 for POCSAG reception on given frequency */
|
||||
void POCSAG_ConfigureRadio(uint32_t frequency_hz);
|
||||
|
||||
/* Stop POCSAG reception, restore normal RX */
|
||||
void POCSAG_Stop(void);
|
||||
|
||||
/* Get state description string */
|
||||
const char *POCSAG_StateString(pocsag_state_t state);
|
||||
|
||||
#endif /* APP_POCSAG_POCSAG_H */
|
||||
Reference in New Issue
Block a user