diff options
Diffstat (limited to 'stacks/max25-bcpr/include/bcpr')
| -rw-r--r-- | stacks/max25-bcpr/include/bcpr/bcpr.h | 16 | ||||
| -rw-r--r-- | stacks/max25-bcpr/include/bcpr/bcpr_config.h | 70 | ||||
| -rw-r--r-- | stacks/max25-bcpr/include/bcpr/bcpr_crc.h | 12 | ||||
| -rw-r--r-- | stacks/max25-bcpr/include/bcpr/bcpr_daemon.h | 23 | ||||
| -rw-r--r-- | stacks/max25-bcpr/include/bcpr/bcpr_engine.h | 62 | ||||
| -rw-r--r-- | stacks/max25-bcpr/include/bcpr/bcpr_hdlc.h | 57 | ||||
| -rw-r--r-- | stacks/max25-bcpr/include/bcpr/bcpr_kiss.h | 17 | ||||
| -rw-r--r-- | stacks/max25-bcpr/include/bcpr/bcpr_lock.h | 22 | ||||
| -rw-r--r-- | stacks/max25-bcpr/include/bcpr/bcpr_runas.h | 12 | ||||
| -rw-r--r-- | stacks/max25-bcpr/include/bcpr/bcpr_ser12.h | 47 | ||||
| -rw-r--r-- | stacks/max25-bcpr/include/bcpr/bcpr_uart.h | 22 |
11 files changed, 360 insertions, 0 deletions
diff --git a/stacks/max25-bcpr/include/bcpr/bcpr.h b/stacks/max25-bcpr/include/bcpr/bcpr.h new file mode 100644 index 0000000..6223796 --- /dev/null +++ b/stacks/max25-bcpr/include/bcpr/bcpr.h @@ -0,0 +1,16 @@ +#ifndef BCPR_H +#define BCPR_H + +#include <stdint.h> +#include <stddef.h> + +#define BCPR_MAX_DEVICES 2 +#define BCPR_SER12_EXTENT 8 +#define BCPR_HDLC_BUF 32 +#define BCPR_MAXFLEN 400 +#define BCPR_MAGIC 0x42525052u /* 'BCPR' */ + +typedef struct bcpr_device bcpr_device_t; +typedef struct bcpr_engine bcpr_engine_t; + +#endif diff --git a/stacks/max25-bcpr/include/bcpr/bcpr_config.h b/stacks/max25-bcpr/include/bcpr/bcpr_config.h new file mode 100644 index 0000000..158bf73 --- /dev/null +++ b/stacks/max25-bcpr/include/bcpr/bcpr_config.h @@ -0,0 +1,70 @@ +#ifndef BCPR_CONFIG_H +#define BCPR_CONFIG_H + +#include "bcpr/bcpr.h" + +/* TXD charge-pump policy (English INI: txd_bias=pulse|steady). */ +enum { + BCPR_TXD_PULSE = 0, /* Sailer/default: THR←0x00 every tick (framing edges) */ + BCPR_TXD_STEADY = 1 /* TFPCX-class experiment: UART break ≈ continuous SPACE */ +}; + +typedef struct bcpr_dev_config { + int enabled; + char serial[64]; + unsigned int iobase; + unsigned int irq; /* real UART IRQ — must match setserial */ + unsigned int baud; + char mode[16]; /* ser12* / ser12 / ser12+ */ + char kiss_link[256]; + int tx_delay; /* 10 ms units */ + int tx_tail; + int slottime; + int ppersist; + int fulldup; + /* + * FlexNet SER12.doc PTT watchdog mirror (cal / sustained key): + * after ptt_wd_key_ms keyed → clear RTS ~ptt_wd_pause_ms → resume. + * Defaults 14500 / 500. ptt_wd=0 disables. + */ + int ptt_wd; + int ptt_wd_key_ms; + int ptt_wd_pause_ms; + int txd_bias; /* BCPR_TXD_* */ + /* + * Software TOT (host policy — not radio TOT): + * max_key_ms = max continuous PTT per burst; + * min_gap_ms = min idle between bursts (matches TX pace); + * max_consecutive = back-to-back bursts (min_gap..session) before trip; + * max_bursts = total bursts before trip (each burst <= max_key_ms). + */ + int tot_enabled; + int tot_max_key_ms; + int tot_min_gap_ms; + int tot_max_consecutive; + int tot_max_bursts; +} bcpr_dev_config_t; + +typedef struct bcpr_config { + bcpr_dev_config_t dev[BCPR_MAX_DEVICES]; + int n_dev; + int dry_run; /* no ioperm / no setserial */ + char state_dir[128]; + char run_user[64]; + char run_group[64]; + /* Global defaults copied onto devices that omit per-bcN keys. */ + int ptt_wd; + int ptt_wd_key_ms; + int ptt_wd_pause_ms; + int txd_bias; + int tot_enabled; + int tot_max_key_ms; + int tot_min_gap_ms; + int tot_max_consecutive; + int tot_max_bursts; +} bcpr_config_t; + +int bcpr_config_load(bcpr_config_t *cfg, const char *path); +void bcpr_config_defaults(bcpr_config_t *cfg); + +#endif diff --git a/stacks/max25-bcpr/include/bcpr/bcpr_crc.h b/stacks/max25-bcpr/include/bcpr/bcpr_crc.h new file mode 100644 index 0000000..5a53b15 --- /dev/null +++ b/stacks/max25-bcpr/include/bcpr/bcpr_crc.h @@ -0,0 +1,12 @@ +#ifndef BCPR_CRC_H +#define BCPR_CRC_H + +#include <stddef.h> +#include <stdint.h> + +/* CRC-CCITT as used by Linux hdlcdrv (good frame residue 0xf0b8). */ +uint16_t bcpr_crc_ccitt(uint16_t crc, const uint8_t *buf, size_t len); +void bcpr_append_crc_ccitt(uint8_t *buffer, int len); +int bcpr_check_crc_ccitt(const uint8_t *buf, int cnt); + +#endif diff --git a/stacks/max25-bcpr/include/bcpr/bcpr_daemon.h b/stacks/max25-bcpr/include/bcpr/bcpr_daemon.h new file mode 100644 index 0000000..360b0ae --- /dev/null +++ b/stacks/max25-bcpr/include/bcpr/bcpr_daemon.h @@ -0,0 +1,23 @@ +#ifndef BCPR_DAEMON_H +#define BCPR_DAEMON_H + +#include "bcpr/bcpr_config.h" +#include "bcpr/bcpr_engine.h" +#include "bcpr/bcpr_kiss.h" + +typedef struct bcpr_daemon_opts { + int dry_run; + int seconds; + int cal_mode; + int cli_txd_bias; + int cli_ptt_wd; + int cli_ptt_wd_key_ms; + int cli_ptt_wd_pause_ms; + int engine_preopened; +} bcpr_daemon_opts_t; + +/* engine_preopened=1: lock/ioperm done in init parent; child after fork. */ +int bcpr_daemon_run(bcpr_config_t *cfg, bcpr_kiss_pty_t *ptys, int npty, + bcpr_engine_t *engine, const bcpr_daemon_opts_t *opts); + +#endif diff --git a/stacks/max25-bcpr/include/bcpr/bcpr_engine.h b/stacks/max25-bcpr/include/bcpr/bcpr_engine.h new file mode 100644 index 0000000..f3b3d4a --- /dev/null +++ b/stacks/max25-bcpr/include/bcpr/bcpr_engine.h @@ -0,0 +1,62 @@ +#ifndef BCPR_ENGINE_H +#define BCPR_ENGINE_H + +#include "bcpr/bcpr_config.h" +#include "bcpr/bcpr_hdlc.h" +#include "bcpr/bcpr_lock.h" +#include "bcpr/bcpr_ser12.h" + +#include <stdint.h> + +struct bcpr_device { + bcpr_dev_config_t cfg; + bcpr_port_lock_t lock; + bcpr_ser12_t ser12; + bcpr_hdlc_t hdlc; + int running; + int index; /* 0 = bc0, 1 = bc1 */ + /* S0 TX telemetry (reset on PTT rise, emit on PTT fall). */ + int ptt_was; + int64_t ptt_on_ns; + unsigned thr_writes; + unsigned max_tick_gap_us; + unsigned last_tick_us; + unsigned tick_count; /* bit ticks while keyed */ + unsigned long long gap_sum_us; /* for mean gap */ + unsigned gaps_gt_2x; /* gaps > 2× baud_us */ + int tx_div_set; /* UART baud_uartdiv applied for this PTT */ + int break_set; /* txd_bias=steady: LCR break asserted */ + /* Software TOT runtime (see tot_* in bcpr_dev_config_t). */ + int tot_tripped; + int tot_burst_total; + int tot_consecutive; + unsigned tot_last_off_us; + unsigned tot_key_start_us; +}; + +typedef void (*bcpr_rx_fn)(int dev_idx, const uint8_t *kiss, int len, void *ud); + +struct bcpr_engine { + bcpr_config_t cfg; + bcpr_device_t dev[BCPR_MAX_DEVICES]; + int n; + volatile int stop; + bcpr_rx_fn on_rx; + void *on_rx_ud; + /* 0 = forever; >0 stop after wall-clock seconds (tests / dry-run). */ + int run_seconds; + /* BCPR_CAL_* on all enabled devices; 0 = normal KISS/HDLC. */ + int cal_mode; +}; + +int bcpr_engine_open(bcpr_engine_t *e, const bcpr_config_t *cfg); +void bcpr_engine_close(bcpr_engine_t *e); +void bcpr_engine_set_rx(bcpr_engine_t *e, bcpr_rx_fn fn, void *ud); +int bcpr_engine_queue_kiss(bcpr_engine_t *e, int dev_idx, const uint8_t *kiss, + int len); +/* Apply DOS-style cal (high/low/alt) before bcpr_engine_run. */ +void bcpr_engine_set_cal(bcpr_engine_t *e, int cal_mode); +/* Run until e->stop or run_seconds elapses. Dry-run skips UART I/O. */ +int bcpr_engine_run(bcpr_engine_t *e); + +#endif diff --git a/stacks/max25-bcpr/include/bcpr/bcpr_hdlc.h b/stacks/max25-bcpr/include/bcpr/bcpr_hdlc.h new file mode 100644 index 0000000..0cf0bfb --- /dev/null +++ b/stacks/max25-bcpr/include/bcpr/bcpr_hdlc.h @@ -0,0 +1,57 @@ +#ifndef BCPR_HDLC_H +#define BCPR_HDLC_H + +#include "bcpr/bcpr.h" +#include <stdint.h> + +typedef struct bcpr_hbuf { + unsigned rd, wr; + uint16_t buf[BCPR_HDLC_BUF]; +} bcpr_hbuf_t; + +typedef struct bcpr_channel { + int tx_delay, tx_tail, slottime, ppersist, fulldup; +} bcpr_channel_t; + +typedef struct bcpr_hdlc { + int bitrate; + bcpr_channel_t ch; + bcpr_hbuf_t rx_hbuf; + bcpr_hbuf_t tx_hbuf; + int rx_state; + unsigned bitstream, bitbuf; + int numbits; + int dcd; + int rx_len; + uint8_t *rx_bp; + uint8_t rx_buffer[BCPR_MAXFLEN + 2]; + int tx_state; + int numflags; + unsigned tx_bitstream; + int ptt; + int slotcnt; + unsigned tx_bitbuf; + int tx_numbits; + int tx_len; + uint8_t *tx_bp; + uint8_t tx_buffer[BCPR_MAXFLEN + 2]; + /* pending KISS payload (without FEND/cmd) queued for TX */ + uint8_t pending[BCPR_MAXFLEN]; + int pending_len; + int have_pending; +} bcpr_hdlc_t; + +void bcpr_hdlc_init(bcpr_hdlc_t *h, int bitrate, const bcpr_channel_t *ch); +void bcpr_hdlc_putbits(bcpr_hdlc_t *h, unsigned bits); +unsigned bcpr_hdlc_getbits(bcpr_hdlc_t *h); +void bcpr_hdlc_receiver(bcpr_hdlc_t *h, + void (*on_frame)(const uint8_t *kiss, int len, void *ud), + void *ud); +void bcpr_hdlc_transmitter(bcpr_hdlc_t *h); +void bcpr_hdlc_arbitrate(bcpr_hdlc_t *h); +int bcpr_hdlc_queue_kiss(bcpr_hdlc_t *h, const uint8_t *kiss, int len); +int bcpr_hdlc_ptt(const bcpr_hdlc_t *h); +/* Force idle TX — drop pending frame and clear keyed state. */ +void bcpr_hdlc_abort_tx(bcpr_hdlc_t *h); + +#endif diff --git a/stacks/max25-bcpr/include/bcpr/bcpr_kiss.h b/stacks/max25-bcpr/include/bcpr/bcpr_kiss.h new file mode 100644 index 0000000..2cdf5eb --- /dev/null +++ b/stacks/max25-bcpr/include/bcpr/bcpr_kiss.h @@ -0,0 +1,17 @@ +#ifndef BCPR_KISS_H +#define BCPR_KISS_H + +#include "bcpr/bcpr.h" + +typedef struct bcpr_kiss_pty { + int master_fd; + int slave_fd; + char link_path[128]; + int idx; +} bcpr_kiss_pty_t; + +int bcpr_kiss_pty_open(bcpr_kiss_pty_t *kp, int idx, const char *link_path, + const char *state_dir); +void bcpr_kiss_pty_close(bcpr_kiss_pty_t *kp); + +#endif diff --git a/stacks/max25-bcpr/include/bcpr/bcpr_lock.h b/stacks/max25-bcpr/include/bcpr/bcpr_lock.h new file mode 100644 index 0000000..fd6c6b7 --- /dev/null +++ b/stacks/max25-bcpr/include/bcpr/bcpr_lock.h @@ -0,0 +1,22 @@ +#ifndef BCPR_LOCK_H +#define BCPR_LOCK_H + +#include "bcpr/bcpr_config.h" + +typedef struct bcpr_port_lock { + char serial[64]; + unsigned iobase; + unsigned irq; + int lock_fd; + int uart_released; + int dry_run; +} bcpr_port_lock_t; + +/* Exclusive COM lock: flock + setserial uart none. irq must match setserial. */ +int bcpr_lock_acquire(bcpr_port_lock_t *lk, const bcpr_dev_config_t *dev, + int dry_run); +void bcpr_lock_release(bcpr_port_lock_t *lk); +int bcpr_lock_verify_irq(const char *serial, unsigned expect_irq, + unsigned *got_irq, unsigned *got_io); + +#endif diff --git a/stacks/max25-bcpr/include/bcpr/bcpr_runas.h b/stacks/max25-bcpr/include/bcpr/bcpr_runas.h new file mode 100644 index 0000000..801dcba --- /dev/null +++ b/stacks/max25-bcpr/include/bcpr/bcpr_runas.h @@ -0,0 +1,12 @@ +#ifndef BCPR_RUNAS_H +#define BCPR_RUNAS_H + +#include "bcpr/bcpr_config.h" + +/* Drop to [max25-bcpr] user=/group= (Linux). Returns 0 or -1. */ +int bcpr_runas_drop(const bcpr_config_t *cfg); + +/* Refuse live start as root — use max25-bcprd-init for hardware. */ +int bcpr_runas_refuse_root(int dry_run); + +#endif diff --git a/stacks/max25-bcpr/include/bcpr/bcpr_ser12.h b/stacks/max25-bcpr/include/bcpr/bcpr_ser12.h new file mode 100644 index 0000000..2b6de8d --- /dev/null +++ b/stacks/max25-bcpr/include/bcpr/bcpr_ser12.h @@ -0,0 +1,47 @@ +#ifndef BCPR_SER12_H +#define BCPR_SER12_H + +#include "bcpr/bcpr_hdlc.h" +#include <stdint.h> + +/* DOS cal.exe style: sticky/toggle DTR bit + RTS PTT (no HDLC). */ +enum { + BCPR_CAL_OFF = 0, + BCPR_CAL_HIGH = 1, + BCPR_CAL_LOW = 2, + BCPR_CAL_ALT = 3 +}; + +typedef struct bcpr_ser12 { + unsigned baud; + unsigned baud_us; + int opt_dcd; /* 0 soft, 1 hard, -1 hard inv */ + unsigned char tx_bit; + unsigned char last_rxbit; + int dcd_sum0, dcd_sum1, dcd_sum2; + int dcd_time; + unsigned pll_time; + unsigned txshreg; + unsigned shreg; + int ptt_hw; /* modem PTT keyed (logical; stays 1 during WD pause) */ + int cal_mode; /* BCPR_CAL_* — bypasses HDLC TX */ + /* FlexNet SER12 PTT WD — see bcpr_ser12_set_ptt_wd(). */ + int ptt_wd; + unsigned ptt_wd_key_us; + unsigned ptt_wd_pause_us; + unsigned ptt_wd_phase_start_us; + int ptt_wd_pausing; /* 1 → force MCR idle (RTS clear) this tick */ +} bcpr_ser12_t; + +void bcpr_ser12_init(bcpr_ser12_t *s, unsigned baud, int opt_dcd); +void bcpr_ser12_set_mode(bcpr_ser12_t *s, const char *mode, unsigned *baud_out); +void bcpr_ser12_set_cal(bcpr_ser12_t *s, int cal_mode); +/* FlexNet defaults: key_ms=14500, pause_ms=500. enable=0 disables. */ +void bcpr_ser12_set_ptt_wd(bcpr_ser12_t *s, int enable, int key_ms, int pause_ms); +/* Software TOT: drop logical+HW PTT immediately. */ +void bcpr_ser12_force_unkey(bcpr_ser12_t *s); +/* One bit-time / tick: sample cts (0/1), drive *mcr_out / *thr_feed */ +void bcpr_ser12_tick(bcpr_ser12_t *s, bcpr_hdlc_t *h, int cts, int *mcr_out, + int *do_thr00, unsigned now_us); + +#endif diff --git a/stacks/max25-bcpr/include/bcpr/bcpr_uart.h b/stacks/max25-bcpr/include/bcpr/bcpr_uart.h new file mode 100644 index 0000000..fde720e --- /dev/null +++ b/stacks/max25-bcpr/include/bcpr/bcpr_uart.h @@ -0,0 +1,22 @@ +#ifndef BCPR_UART_H +#define BCPR_UART_H + +#include <stdint.h> + +/* When set, all UART I/O is a no-op (CI / --dry-run). */ +void bcpr_uart_set_dry_run(int on); +int bcpr_uart_ioperm(unsigned iobase, int on); +void bcpr_uart_outb(unsigned char val, unsigned port); +unsigned char bcpr_uart_inb(unsigned port); +void bcpr_uart_set_divisor(unsigned iobase, unsigned divisor); +void bcpr_uart_open_ser12(unsigned iobase); +void bcpr_uart_close_ser12(unsigned iobase); +unsigned char bcpr_uart_msr(unsigned iobase); +void bcpr_uart_mcr(unsigned iobase, unsigned char v); +void bcpr_uart_thr00(unsigned iobase); +/* LCR bit6 Set Break — force TXD continuous SPACE (RS-232 +V). Clear = normal. */ +void bcpr_uart_set_break(unsigned iobase, int on); +/* Poll LSR bit5 (THRE) until set or timeout_us. Returns 1 if empty, 0 on timeout. */ +int bcpr_uart_wait_thre(unsigned iobase, unsigned timeout_us); + +#endif |
