summaryrefslogtreecommitdiff
path: root/stacks/max25-bcpr/include
diff options
context:
space:
mode:
Diffstat (limited to 'stacks/max25-bcpr/include')
-rw-r--r--stacks/max25-bcpr/include/bcpr/bcpr.h16
-rw-r--r--stacks/max25-bcpr/include/bcpr/bcpr_config.h70
-rw-r--r--stacks/max25-bcpr/include/bcpr/bcpr_crc.h12
-rw-r--r--stacks/max25-bcpr/include/bcpr/bcpr_daemon.h23
-rw-r--r--stacks/max25-bcpr/include/bcpr/bcpr_engine.h62
-rw-r--r--stacks/max25-bcpr/include/bcpr/bcpr_hdlc.h57
-rw-r--r--stacks/max25-bcpr/include/bcpr/bcpr_kiss.h17
-rw-r--r--stacks/max25-bcpr/include/bcpr/bcpr_lock.h22
-rw-r--r--stacks/max25-bcpr/include/bcpr/bcpr_runas.h12
-rw-r--r--stacks/max25-bcpr/include/bcpr/bcpr_ser12.h47
-rw-r--r--stacks/max25-bcpr/include/bcpr/bcpr_uart.h22
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
git clone -b <branch> https://cgit.mode42.com/<repo>.git
git clone -b <branch> git://cgit.mode42.com/<repo>.git

info@mode42.com