summaryrefslogtreecommitdiff
path: root/plugins/packet_radio/packet_radio_config.c
diff options
context:
space:
mode:
authorinfo@mode42.com <info@mode42.com>2026-08-08 03:54:55 +0000
committerinfo@mode42.com <info@mode42.com>2026-08-08 03:54:55 +0000
commit20cb29c2f8c5c87bc590896854a20b1473ceb358 (patch)
tree2857f41513a56ad41af97b57362639298aa7f033 /plugins/packet_radio/packet_radio_config.c
#2
Diffstat (limited to 'plugins/packet_radio/packet_radio_config.c')
-rw-r--r--plugins/packet_radio/packet_radio_config.c786
1 files changed, 786 insertions, 0 deletions
diff --git a/plugins/packet_radio/packet_radio_config.c b/plugins/packet_radio/packet_radio_config.c
new file mode 100644
index 0000000..f8e2d65
--- /dev/null
+++ b/plugins/packet_radio/packet_radio_config.c
@@ -0,0 +1,786 @@
+#include "hybbx/packet_radio.h"
+#include "hybbx/tnc.h"
+#include "hybbx/circuit.h"
+#include "hybbx/util.h"
+#include "hybbx/log.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+static char *hybbx_strdup(const char *s)
+{
+ size_t len;
+ char *copy;
+
+ if (s == NULL) {
+ return NULL;
+ }
+
+ len = strlen(s) + 1;
+ copy = malloc(len);
+ if (copy != NULL) {
+ memcpy(copy, s, len);
+ }
+ return copy;
+}
+
+static int str_ieq(const char *a, const char *b)
+{
+ if (a == NULL || b == NULL) {
+ return 0;
+ }
+
+ while (*a != '\0' && *b != '\0') {
+ char ca = (char)(*a >= 'A' && *a <= 'Z' ? *a + 32 : *a);
+ char cb = (char)(*b >= 'A' && *b <= 'Z' ? *b + 32 : *b);
+
+ if (ca != cb) {
+ return 0;
+ }
+ a++;
+ b++;
+ }
+
+ return *a == '\0' && *b == '\0';
+}
+
+static const char *find_kv(const char *config, const char *key,
+ char *scratch, size_t scratch_len)
+{
+ const char *cursor = config;
+ size_t key_len = strlen(key);
+
+ if (config == NULL || key == NULL) {
+ return NULL;
+ }
+
+ while (*cursor != '\0') {
+ const char *sep = strchr(cursor, ';');
+ const char *end = sep != NULL ? sep : cursor + strlen(cursor);
+ const char *eq = strchr(cursor, '=');
+
+ if (eq != NULL && eq < end && (size_t)(eq - cursor) == key_len &&
+ strncmp(cursor, key, key_len) == 0) {
+ const char *value = eq + 1;
+ size_t value_len = (size_t)(end - value);
+
+ if (value_len >= scratch_len) {
+ value_len = scratch_len - 1;
+ }
+ memcpy(scratch, value, value_len);
+ scratch[value_len] = '\0';
+ return scratch;
+ }
+
+ if (sep == NULL) {
+ break;
+ }
+ cursor = sep + 1;
+ }
+
+ return NULL;
+}
+
+int hybbx_packet_radio_section_is_local_edge(const char *config)
+{
+ char scratch[64];
+
+ if (config == NULL) {
+ return 0;
+ }
+
+ if (find_kv(config, "circuit_host", scratch, sizeof(scratch)) != NULL) {
+ return 1;
+ }
+ if (find_kv(config, "device", scratch, sizeof(scratch)) != NULL) {
+ return 1;
+ }
+ if (find_kv(config, "tnc", scratch, sizeof(scratch)) != NULL) {
+ return 1;
+ }
+ if (find_kv(config, "protocol", scratch, sizeof(scratch)) != NULL) {
+ return 1;
+ }
+
+ return 0;
+}
+
+static hybbx_packet_radio_device_type_t parse_device_type(const char *value)
+{
+ if (value == NULL) {
+ return HYBBX_PACKET_RADIO_DEVICE_USB;
+ }
+
+ if (str_ieq(value, "usb") || str_ieq(value, "ax25") ||
+ str_ieq(value, "ax.25")) {
+ return HYBBX_PACKET_RADIO_DEVICE_USB;
+ }
+
+ if (str_ieq(value, "serial") || str_ieq(value, "com") ||
+ str_ieq(value, "rs232") || str_ieq(value, "v24")) {
+ return HYBBX_PACKET_RADIO_DEVICE_SERIAL;
+ }
+
+ return HYBBX_PACKET_RADIO_DEVICE_USB;
+}
+
+static const char *default_device_for_type(hybbx_packet_radio_device_type_t type)
+{
+ if (type == HYBBX_PACKET_RADIO_DEVICE_SERIAL) {
+ return HYBBX_PACKET_RADIO_DEFAULT_DEVICE_SERIAL;
+ }
+ return HYBBX_PACKET_RADIO_DEFAULT_DEVICE_USB;
+}
+
+static hybbx_packet_radio_tnc_t parse_tnc(const char *value)
+{
+ if (value == NULL || str_ieq(value, "tnc2c") || str_ieq(value, "tnc2-c")) {
+ return HYBBX_PACKET_RADIO_TNC_TNC2C;
+ }
+
+ if (str_ieq(value, "tnc2") || str_ieq(value, "tnc-2") ||
+ str_ieq(value, "pktnc2") || str_ieq(value, "pk-tnc2") ||
+ str_ieq(value, "tapr") || str_ieq(value, "thefirmware") ||
+ str_ieq(value, "tf")) {
+ return HYBBX_PACKET_RADIO_TNC_TNC2;
+ }
+
+ if (str_ieq(value, "pk232") || str_ieq(value, "pk-232") ||
+ str_ieq(value, "aea") || str_ieq(value, "pk87") ||
+ str_ieq(value, "pk-87")) {
+ return HYBBX_PACKET_RADIO_TNC_PK232;
+ }
+
+ if (str_ieq(value, "mfj1278") || str_ieq(value, "mfj-1278") ||
+ str_ieq(value, "mfj1278b") || str_ieq(value, "mfj")) {
+ return HYBBX_PACKET_RADIO_TNC_MFJ1278;
+ }
+
+ if (str_ieq(value, "kantronics") || str_ieq(value, "kpc") ||
+ str_ieq(value, "kpc3") || str_ieq(value, "kpc9612")) {
+ return HYBBX_PACKET_RADIO_TNC_KANTRONICS;
+ }
+
+ if (str_ieq(value, "baycom") || str_ieq(value, "bay-com")) {
+ return HYBBX_PACKET_RADIO_TNC_BAYCOM;
+ }
+
+ if (str_ieq(value, "pccom") || str_ieq(value, "pc-com") ||
+ str_ieq(value, "albrecht")) {
+ return HYBBX_PACKET_RADIO_TNC_PCCOM;
+ }
+
+ if (str_ieq(value, "generic") || str_ieq(value, "tnc")) {
+ return HYBBX_PACKET_RADIO_TNC_GENERIC;
+ }
+
+ return HYBBX_PACKET_RADIO_TNC_TNC2C;
+}
+
+static hybbx_packet_radio_protocol_t parse_protocol(const char *value)
+{
+ if (value == NULL || str_ieq(value, "kiss")) {
+ return HYBBX_PACKET_RADIO_PROTO_KISS;
+ }
+
+ if (str_ieq(value, "hostmode") || str_ieq(value, "host") ||
+ str_ieq(value, "tnc2")) {
+ return HYBBX_PACKET_RADIO_PROTO_HOSTMODE;
+ }
+
+ if (str_ieq(value, "6pack") || str_ieq(value, "sixpack")) {
+ return HYBBX_PACKET_RADIO_PROTO_SIXPACK;
+ }
+
+ return HYBBX_PACKET_RADIO_PROTO_KISS;
+}
+
+static hybbx_tnc2c_modem_t parse_modem(const char *value)
+{
+ if (value == NULL || str_ieq(value, "tcm3105") || str_ieq(value, "1200")) {
+ return HYBBX_TNC2C_MODEM_TCM3105;
+ }
+
+ if (str_ieq(value, "9600")) {
+ return HYBBX_TNC2C_MODEM_9600;
+ }
+
+ if (str_ieq(value, "g3ruh") || str_ieq(value, "g3ruh_fsk") ||
+ str_ieq(value, "fsk9600")) {
+ return HYBBX_TNC2C_MODEM_9600;
+ }
+
+ if (str_ieq(value, "19200")) {
+ return HYBBX_TNC2C_MODEM_19200;
+ }
+
+ return HYBBX_TNC2C_MODEM_TCM3105;
+}
+
+static float parse_clock_mhz(const char *value)
+{
+ if (value == NULL) {
+ return HYBBX_TNC2C_CLOCK_4_9_MHZ;
+ }
+
+ if (str_ieq(value, "9.8") || str_ieq(value, "9,8")) {
+ return HYBBX_TNC2C_CLOCK_9_8_MHZ;
+ }
+
+ if (str_ieq(value, "10") || str_ieq(value, "10.0")) {
+ return HYBBX_TNC2C_CLOCK_10_MHZ;
+ }
+
+ return HYBBX_TNC2C_CLOCK_4_9_MHZ;
+}
+
+static unsigned int parse_uint(const char *value, unsigned int default_value)
+{
+ char *end = NULL;
+ unsigned long n;
+
+ if (value == NULL || value[0] == '\0') {
+ return default_value;
+ }
+
+ n = strtoul(value, &end, 10);
+ if (end == value || n == 0) {
+ return default_value;
+ }
+
+ return (unsigned int)n;
+}
+
+static hybbx_packet_radio_band_t parse_radio_band(const char *value)
+{
+ if (value == NULL || value[0] == '\0') {
+ return HYBBX_PACKET_RADIO_BAND_UNSET;
+ }
+
+ if (str_ieq(value, "cb") || str_ieq(value, "11m") ||
+ str_ieq(value, "27mhz") || str_ieq(value, "citizen")) {
+ return HYBBX_PACKET_RADIO_BAND_CB;
+ }
+
+ if (str_ieq(value, "amateur") || str_ieq(value, "ham") ||
+ str_ieq(value, "amateurfunk") || str_ieq(value, "afu")) {
+ return HYBBX_PACKET_RADIO_BAND_AMATEUR;
+ }
+
+ return HYBBX_PACKET_RADIO_BAND_UNSET;
+}
+
+static hybbx_packet_radio_duplex_t parse_radio_duplex(const char *value)
+{
+ if (value == NULL || value[0] == '\0') {
+ return HYBBX_PACKET_RADIO_DUPLEX_UNSET;
+ }
+
+ if (str_ieq(value, "full") || str_ieq(value, "full-duplex") ||
+ str_ieq(value, "fullduplex") || str_ieq(value, "fulldup")) {
+ return HYBBX_PACKET_RADIO_DUPLEX_FULL;
+ }
+
+ if (str_ieq(value, "half") || str_ieq(value, "half-duplex") ||
+ str_ieq(value, "duplex") || str_ieq(value, "simplex")) {
+ return HYBBX_PACKET_RADIO_DUPLEX_HALF;
+ }
+
+ return HYBBX_PACKET_RADIO_DUPLEX_UNSET;
+}
+
+static hybbx_packet_radio_modulation_t parse_modulation(const char *value)
+{
+ if (value == NULL || value[0] == '\0') {
+ return HYBBX_PACKET_RADIO_MOD_UNSET;
+ }
+
+ if (str_ieq(value, "g3ruh") || str_ieq(value, "g3ruh_fsk") ||
+ str_ieq(value, "fsk9600") || str_ieq(value, "9600fsk")) {
+ return HYBBX_PACKET_RADIO_MOD_G3RUH_FSK;
+ }
+
+ if (str_ieq(value, "afsk") || str_ieq(value, "bell202") ||
+ str_ieq(value, "tcm3105") || str_ieq(value, "1200")) {
+ return HYBBX_PACKET_RADIO_MOD_AFSK;
+ }
+
+ return HYBBX_PACKET_RADIO_MOD_UNSET;
+}
+
+static hybbx_tnc_serial_parity_t parse_serial_parity(const char *value)
+{
+ if (value == NULL || value[0] == '\0') {
+ return HYBBX_TNC_SERIAL_PARITY_UNSET;
+ }
+
+ if (str_ieq(value, "even") || str_ieq(value, "e")) {
+ return HYBBX_TNC_SERIAL_PARITY_EVEN;
+ }
+
+ if (str_ieq(value, "odd") || str_ieq(value, "o")) {
+ return HYBBX_TNC_SERIAL_PARITY_ODD;
+ }
+
+ if (str_ieq(value, "none") || str_ieq(value, "n") || str_ieq(value, "off")) {
+ return HYBBX_TNC_SERIAL_PARITY_NONE;
+ }
+
+ return HYBBX_TNC_SERIAL_PARITY_UNSET;
+}
+
+static void apply_serial_line(hybbx_packet_radio_config_t *out, const char *value)
+{
+ if (value == NULL || value[0] == '\0') {
+ return;
+ }
+
+ if (str_ieq(value, "7e1")) {
+ out->params.data_bits = 7;
+ out->params.serial_parity = HYBBX_TNC_SERIAL_PARITY_EVEN;
+ out->params.stop_bits = 1;
+ return;
+ }
+
+ if (str_ieq(value, "8n1")) {
+ out->params.data_bits = 8;
+ out->params.serial_parity = HYBBX_TNC_SERIAL_PARITY_NONE;
+ out->params.stop_bits = 1;
+ return;
+ }
+
+ if (str_ieq(value, "7o1")) {
+ out->params.data_bits = 7;
+ out->params.serial_parity = HYBBX_TNC_SERIAL_PARITY_ODD;
+ out->params.stop_bits = 1;
+ }
+}
+
+static hybbx_kiss_entry_t parse_kiss_entry(const char *value)
+{
+ if (value == NULL || value[0] == '\0') {
+ return HYBBX_KISS_ENTRY_UNSET;
+ }
+
+ if (str_ieq(value, "none") || str_ieq(value, "skip") ||
+ str_ieq(value, "off") || str_ieq(value, "no")) {
+ return HYBBX_KISS_ENTRY_NONE;
+ }
+
+ if (str_ieq(value, "kiss_on") || str_ieq(value, "kiss-on") ||
+ str_ieq(value, "command") || str_ieq(value, "on") ||
+ str_ieq(value, "yes")) {
+ return HYBBX_KISS_ENTRY_KISS_ON;
+ }
+
+ if (str_ieq(value, "esc_at_k") || str_ieq(value, "esc@k") ||
+ str_ieq(value, "esc") || str_ieq(value, "@k")) {
+ return HYBBX_KISS_ENTRY_ESC_AT_K;
+ }
+
+ if (str_ieq(value, "auto")) {
+ return HYBBX_KISS_ENTRY_AUTO;
+ }
+
+ return HYBBX_KISS_ENTRY_UNSET;
+}
+
+static hybbx_kiss_exit_t parse_kiss_exit(const char *value)
+{
+ if (value == NULL || value[0] == '\0') {
+ return HYBBX_KISS_EXIT_UNSET;
+ }
+
+ if (str_ieq(value, "none") || str_ieq(value, "skip") ||
+ str_ieq(value, "off") || str_ieq(value, "no")) {
+ return HYBBX_KISS_EXIT_NONE;
+ }
+
+ if (str_ieq(value, "kiss_off") || str_ieq(value, "kiss-off") ||
+ str_ieq(value, "command")) {
+ return HYBBX_KISS_EXIT_KISS_OFF;
+ }
+
+ if (str_ieq(value, "kiss_frame") || str_ieq(value, "frame") ||
+ str_ieq(value, "fend")) {
+ return HYBBX_KISS_EXIT_KISS_FRAME;
+ }
+
+ if (str_ieq(value, "auto")) {
+ return HYBBX_KISS_EXIT_AUTO;
+ }
+
+ return HYBBX_KISS_EXIT_UNSET;
+}
+
+static unsigned int default_radio_baud_for_modem(hybbx_tnc2c_modem_t modem)
+{
+ switch (modem) {
+ case HYBBX_TNC2C_MODEM_9600:
+ return 9600;
+ case HYBBX_TNC2C_MODEM_19200:
+ return 19200;
+ case HYBBX_TNC2C_MODEM_TCM3105:
+ default:
+ return HYBBX_TNC2C_DEFAULT_RADIO_BAUD;
+ }
+}
+
+static hybbx_result_t parse_via_list(hybbx_packet_radio_config_t *out,
+ const char *value)
+{
+ char scratch[256];
+ char *cursor;
+ char *token;
+
+ if (value == NULL || value[0] == '\0') {
+ return HYBBX_OK;
+ }
+
+ if (strlen(value) >= sizeof(scratch)) {
+ return HYBBX_ERR_INVALID;
+ }
+
+ memcpy(scratch, value, strlen(value) + 1);
+ cursor = scratch;
+
+ while ((token = strtok(cursor, ",")) != NULL && out->via_count < HYBBX_PACKET_RADIO_VIA_MAX) {
+ char *item = hybbx_strdup(token);
+ if (item == NULL) {
+ return HYBBX_ERR_NOMEM;
+ }
+ out->via[out->via_count++] = item;
+ cursor = NULL;
+ }
+
+ return HYBBX_OK;
+}
+
+int hybbx_packet_radio_baud_valid(unsigned int baud)
+{
+ return baud > 0;
+}
+
+hybbx_result_t hybbx_packet_radio_config_parse(const char *config,
+ hybbx_packet_radio_config_t *out)
+{
+ char scratch[256];
+ const char *value;
+ unsigned long baud;
+ hybbx_result_t rc;
+
+ if (out == NULL) {
+ return HYBBX_ERR_INVALID;
+ }
+
+ memset(out, 0, sizeof(*out));
+
+ out->tnc = HYBBX_PACKET_RADIO_TNC_TNC2C;
+ out->protocol = 0; /* profile may choose */
+ out->params.clock_mhz = HYBBX_TNC2C_CLOCK_4_9_MHZ;
+ out->params.modem = HYBBX_TNC2C_MODEM_TCM3105;
+ out->params.radio_baud = HYBBX_TNC2C_DEFAULT_RADIO_BAUD;
+ out->params.kiss_port = 0;
+ out->params.txdelay = 50;
+ out->params.persist = 0;
+ out->params.slot = 10;
+ out->params.txtail = 0;
+ out->params.band = HYBBX_PACKET_RADIO_BAND_UNSET;
+ out->params.duplex = HYBBX_PACKET_RADIO_DUPLEX_UNSET;
+ out->params.modulation = HYBBX_PACKET_RADIO_MOD_UNSET;
+ out->params.kiss_entry = HYBBX_KISS_ENTRY_UNSET;
+ out->params.kiss_exit = HYBBX_KISS_EXIT_UNSET;
+ out->params.host_connect_on_start = 0;
+ out->params.assert_modem_lines = -1;
+
+ value = find_kv(config, "device_type", scratch, sizeof(scratch));
+ out->device_type = parse_device_type(value);
+
+ value = find_kv(config, "device", scratch, sizeof(scratch));
+ if (value == NULL) {
+ out->device = hybbx_strdup(default_device_for_type(out->device_type));
+ } else {
+ out->device = hybbx_strdup(value);
+ }
+
+ if (out->device == NULL) {
+ hybbx_packet_radio_config_free(out);
+ return HYBBX_ERR_NOMEM;
+ }
+
+ value = find_kv(config, "baud", scratch, sizeof(scratch));
+ if (value == NULL || value[0] == '\0') {
+ out->baud = HYBBX_PACKET_RADIO_DEFAULT_BAUD;
+ } else {
+ baud = strtoul(value, NULL, 10);
+ if (!hybbx_packet_radio_baud_valid((unsigned int)baud)) {
+ hybbx_packet_radio_config_free(out);
+ return HYBBX_ERR_INVALID;
+ }
+ out->baud = (unsigned int)baud;
+ }
+
+ value = find_kv(config, "tnc", scratch, sizeof(scratch));
+ out->tnc = parse_tnc(value);
+
+ if (out->tnc == HYBBX_PACKET_RADIO_TNC_BAYCOM ||
+ out->tnc == HYBBX_PACKET_RADIO_TNC_PCCOM) {
+ hybbx_log_warn("[packet_radio] tnc=%s is not a packet_radio profile — "
+ "use tnc=tnc2c (or generic) with kiss_entry=none after "
+ "max25d prep; BayCom/based SER12 = MAX25 max25e0 (bcpr), "
+ "optional [networks] baycom=yes on non-UN1TME sites only",
+ hybbx_packet_radio_tnc_name(out->tnc));
+ hybbx_packet_radio_config_free(out);
+ return HYBBX_ERR_INVALID;
+ }
+
+ value = find_kv(config, "protocol", scratch, sizeof(scratch));
+ if (value != NULL) {
+ out->protocol = parse_protocol(value);
+ }
+
+ value = find_kv(config, "clock_mhz", scratch, sizeof(scratch));
+ out->params.clock_mhz = parse_clock_mhz(value);
+
+ value = find_kv(config, "modem", scratch, sizeof(scratch));
+ out->params.modem = parse_modem(value);
+
+ value = find_kv(config, "radio_baud", scratch, sizeof(scratch));
+ if (value == NULL) {
+ out->params.radio_baud = default_radio_baud_for_modem(out->params.modem);
+ } else {
+ unsigned int radio_baud = parse_uint(value, 0);
+ if (!hybbx_packet_radio_baud_valid(radio_baud)) {
+ hybbx_packet_radio_config_free(out);
+ return HYBBX_ERR_INVALID;
+ }
+ out->params.radio_baud = radio_baud;
+ }
+
+ value = find_kv(config, "kiss_port", scratch, sizeof(scratch));
+ out->params.kiss_port = parse_uint(value, 0);
+
+ value = find_kv(config, "txdelay", scratch, sizeof(scratch));
+ out->params.txdelay = parse_uint(value, out->params.txdelay);
+
+ value = find_kv(config, "persist", scratch, sizeof(scratch));
+ out->params.persist = parse_uint(value, out->params.persist);
+
+ value = find_kv(config, "slot", scratch, sizeof(scratch));
+ out->params.slot = parse_uint(value, out->params.slot);
+
+ value = find_kv(config, "txtail", scratch, sizeof(scratch));
+ out->params.txtail = parse_uint(value, out->params.txtail);
+
+ value = find_kv(config, "radio_band", scratch, sizeof(scratch));
+ if (value != NULL) {
+ out->params.band = parse_radio_band(value);
+ }
+
+ value = find_kv(config, "radio_duplex", scratch, sizeof(scratch));
+ if (value == NULL) {
+ value = find_kv(config, "duplex", scratch, sizeof(scratch));
+ }
+ if (value != NULL) {
+ out->params.duplex = parse_radio_duplex(value);
+ }
+
+ value = find_kv(config, "fullduplex", scratch, sizeof(scratch));
+ if (value != NULL &&
+ out->params.duplex == HYBBX_PACKET_RADIO_DUPLEX_UNSET) {
+ out->params.duplex = hybbx_parse_bool(value, 0) ?
+ HYBBX_PACKET_RADIO_DUPLEX_FULL :
+ HYBBX_PACKET_RADIO_DUPLEX_HALF;
+ }
+
+ value = find_kv(config, "g3ruh_fsk", scratch, sizeof(scratch));
+ if (value != NULL) {
+ out->params.modulation = hybbx_parse_bool(value, 0) ?
+ HYBBX_PACKET_RADIO_MOD_G3RUH_FSK :
+ HYBBX_PACKET_RADIO_MOD_AFSK;
+ }
+
+ value = find_kv(config, "modulation", scratch, sizeof(scratch));
+ if (value != NULL) {
+ hybbx_packet_radio_modulation_t mod = parse_modulation(value);
+ if (mod != HYBBX_PACKET_RADIO_MOD_UNSET) {
+ out->params.modulation = mod;
+ }
+ }
+
+ value = find_kv(config, "kiss_entry", scratch, sizeof(scratch));
+ if (value != NULL) {
+ hybbx_kiss_entry_t kiss_entry = parse_kiss_entry(value);
+ if (kiss_entry != HYBBX_KISS_ENTRY_UNSET) {
+ out->params.kiss_entry = kiss_entry;
+ }
+ }
+
+ value = find_kv(config, "kiss_exit", scratch, sizeof(scratch));
+ if (value != NULL) {
+ hybbx_kiss_exit_t kiss_exit = parse_kiss_exit(value);
+ if (kiss_exit != HYBBX_KISS_EXIT_UNSET) {
+ out->params.kiss_exit = kiss_exit;
+ }
+ }
+
+ value = find_kv(config, "host_connect", scratch, sizeof(scratch));
+ out->params.host_connect_on_start = hybbx_parse_bool(value,
+ out->params.host_connect_on_start);
+
+ value = find_kv(config, "serial_line", scratch, sizeof(scratch));
+ if (value != NULL) {
+ apply_serial_line(out, value);
+ }
+
+ value = find_kv(config, "data_bits", scratch, sizeof(scratch));
+ if (value != NULL && value[0] != '\0') {
+ unsigned int data_bits = parse_uint(value, 0);
+ if (data_bits == 7 || data_bits == 8) {
+ out->params.data_bits = data_bits;
+ }
+ }
+
+ value = find_kv(config, "parity", scratch, sizeof(scratch));
+ if (value != NULL) {
+ hybbx_tnc_serial_parity_t parity = parse_serial_parity(value);
+ if (parity != HYBBX_TNC_SERIAL_PARITY_UNSET) {
+ out->params.serial_parity = parity;
+ }
+ }
+
+ value = find_kv(config, "stop_bits", scratch, sizeof(scratch));
+ if (value != NULL && value[0] != '\0') {
+ unsigned int stop_bits = parse_uint(value, 0);
+ if (stop_bits == 1 || stop_bits == 2) {
+ out->params.stop_bits = stop_bits;
+ }
+ }
+
+ value = find_kv(config, "assert_modem_lines", scratch, sizeof(scratch));
+ if (value == NULL) {
+ value = find_kv(config, "rts_dtr", scratch, sizeof(scratch));
+ }
+ if (value != NULL) {
+ out->params.assert_modem_lines = hybbx_parse_bool(value, 0) ? 1 : 0;
+ }
+
+ value = find_kv(config, "mycall", scratch, sizeof(scratch));
+ if (value != NULL && value[0] != '\0') {
+ out->mycall = hybbx_strdup(value);
+ if (out->mycall == NULL) {
+ hybbx_packet_radio_config_free(out);
+ return HYBBX_ERR_NOMEM;
+ }
+ }
+
+ value = find_kv(config, "dest", scratch, sizeof(scratch));
+ if (value == NULL) {
+ value = find_kv(config, "dest_call", scratch, sizeof(scratch));
+ }
+ if (value != NULL && value[0] != '\0') {
+ out->dest_call = hybbx_strdup(value);
+ if (out->dest_call == NULL) {
+ hybbx_packet_radio_config_free(out);
+ return HYBBX_ERR_NOMEM;
+ }
+ }
+
+ value = find_kv(config, "via", scratch, sizeof(scratch));
+ rc = parse_via_list(out, value);
+ if (rc != HYBBX_OK) {
+ hybbx_packet_radio_config_free(out);
+ return rc;
+ }
+
+ value = find_kv(config, "circuit_host", scratch, sizeof(scratch));
+ if (value != NULL && value[0] != '\0') {
+ out->circuit_host = hybbx_strdup(value);
+ if (out->circuit_host == NULL) {
+ hybbx_packet_radio_config_free(out);
+ return HYBBX_ERR_NOMEM;
+ }
+ }
+
+ value = find_kv(config, "circuit_port", scratch, sizeof(scratch));
+ if (value != NULL && value[0] != '\0') {
+ out->circuit_port = parse_uint(value, HYBBX_CIRCUIT_DEFAULT_PORT);
+ }
+
+ if (out->circuit_port == 0) {
+ out->circuit_port = HYBBX_CIRCUIT_DEFAULT_PORT;
+ }
+ if (out->circuit_host == NULL) {
+ out->circuit_host = hybbx_strdup("127.0.0.1");
+ if (out->circuit_host == NULL) {
+ hybbx_packet_radio_config_free(out);
+ return HYBBX_ERR_NOMEM;
+ }
+ }
+
+ value = find_kv(config, "link_id", scratch, sizeof(scratch));
+ if (value != NULL && value[0] != '\0') {
+ out->link_id = hybbx_strdup(value);
+ if (out->link_id == NULL) {
+ hybbx_packet_radio_config_free(out);
+ return HYBBX_ERR_NOMEM;
+ }
+ }
+
+ value = find_kv(config, "link_password", scratch, sizeof(scratch));
+ if (value != NULL && value[0] != '\0') {
+ out->link_password = hybbx_strdup(value);
+ if (out->link_password == NULL) {
+ hybbx_packet_radio_config_free(out);
+ return HYBBX_ERR_NOMEM;
+ }
+ }
+
+ value = find_kv(config, "link_role", scratch, sizeof(scratch));
+ if (value != NULL && value[0] != '\0') {
+ out->link_role = hybbx_strdup(value);
+ if (out->link_role == NULL) {
+ hybbx_packet_radio_config_free(out);
+ return HYBBX_ERR_NOMEM;
+ }
+ }
+
+ value = find_kv(config, "frequency_mhz", scratch, sizeof(scratch));
+ if (value == NULL || value[0] == '\0') {
+ value = find_kv(config, "frequency", scratch, sizeof(scratch));
+ }
+ if (value != NULL && value[0] != '\0') {
+ out->frequency_mhz = hybbx_strdup(value);
+ if (out->frequency_mhz == NULL) {
+ hybbx_packet_radio_config_free(out);
+ return HYBBX_ERR_NOMEM;
+ }
+ }
+
+ (void)hybbx_tnc_profile_apply_defaults(out);
+ return HYBBX_OK;
+}
+
+void hybbx_packet_radio_config_free(hybbx_packet_radio_config_t *config)
+{
+ unsigned i;
+
+ if (config == NULL) {
+ return;
+ }
+
+ free(config->device);
+ free(config->mycall);
+ free(config->dest_call);
+ free(config->circuit_host);
+ free(config->link_id);
+ free(config->link_password);
+ free(config->link_role);
+ free(config->frequency_mhz);
+ for (i = 0; i < config->via_count; i++) {
+ free(config->via[i]);
+ config->via[i] = NULL;
+ }
+
+ memset(config, 0, sizeof(*config));
+}
git clone -b <branch> https://cgit.mode42.com/<repo>.git
git clone -b <branch> git://cgit.mode42.com/<repo>.git

info@mode42.com