summaryrefslogtreecommitdiff
path: root/plugins/baycom/baycom_config.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/baycom/baycom_config.c')
-rw-r--r--plugins/baycom/baycom_config.c395
1 files changed, 395 insertions, 0 deletions
diff --git a/plugins/baycom/baycom_config.c b/plugins/baycom/baycom_config.c
new file mode 100644
index 0000000..4e740f1
--- /dev/null
+++ b/plugins/baycom/baycom_config.c
@@ -0,0 +1,395 @@
+#include "hybbx/baycom.h"
+#include "hybbx/circuit.h"
+#include "hybbx/util.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static char *baycom_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 char *baycom_normalize_kiss_path(const char *device)
+{
+ static const struct {
+ const char *from;
+ const char *to;
+ } map[] = {
+ {"/tmp/bcpr/", "/tmp/max25-bcpr/"},
+ {"/tmp/bcpr", "/tmp/max25-bcpr"},
+ {"/var/run/bcpr/", "/tmp/max25-bcpr/"},
+ {"/var/run/bcpr", "/tmp/max25-bcpr"},
+ };
+ size_t i;
+ size_t flen;
+ char *norm;
+
+ if (device == NULL || device[0] == '\0') {
+ return NULL;
+ }
+
+ for (i = 0; i < sizeof(map) / sizeof(map[0]); i++) {
+ flen = strlen(map[i].from);
+ if (strncmp(device, map[i].from, flen) != 0) {
+ continue;
+ }
+ if (device[flen] != '\0' && device[flen] != '/') {
+ continue;
+ }
+ norm = malloc(strlen(map[i].to) + strlen(device + flen) + 1);
+ if (norm == NULL) {
+ return baycom_strdup(device);
+ }
+ snprintf(norm, strlen(map[i].to) + strlen(device + flen) + 1, "%s%s",
+ map[i].to, device + flen);
+ return norm;
+ }
+
+ return baycom_strdup(device);
+}
+
+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;
+}
+
+const char *hybbx_baycom_backend_name(hybbx_baycom_backend_t backend)
+{
+ switch (backend) {
+ case HYBBX_BAYCOM_BACKEND_KISS:
+ return "kiss";
+ case HYBBX_BAYCOM_BACKEND_KERNEL:
+ default:
+ return "kernel";
+ }
+}
+
+const char *hybbx_baycom_modem_mode_name(hybbx_baycom_modem_mode_t mode)
+{
+ switch (mode) {
+ case HYBBX_BAYCOM_MODE_SER12_SOFTDCD:
+ return "ser12*";
+ case HYBBX_BAYCOM_MODE_SER12_INV:
+ return "ser12+";
+ case HYBBX_BAYCOM_MODE_SER12HDX:
+ return "ser12hdx";
+ case HYBBX_BAYCOM_MODE_PAR96:
+ return "par96";
+ case HYBBX_BAYCOM_MODE_PAR96_SOFTDCD:
+ return "par96*";
+ case HYBBX_BAYCOM_MODE_EPP:
+ return "epp";
+ case HYBBX_BAYCOM_MODE_SER12:
+ default:
+ return "ser12";
+ }
+}
+
+static hybbx_baycom_backend_t parse_backend(const char *value)
+{
+ if (value == NULL || str_ieq(value, "kernel") || str_ieq(value, "hdlc") ||
+ str_ieq(value, "prstack") || str_ieq(value, "l2")) {
+ return HYBBX_BAYCOM_BACKEND_KERNEL;
+ }
+
+ if (str_ieq(value, "kiss") || str_ieq(value, "serial")) {
+ return HYBBX_BAYCOM_BACKEND_KISS;
+ }
+
+ return HYBBX_BAYCOM_BACKEND_KERNEL;
+}
+
+static hybbx_baycom_modem_mode_t parse_mode(const char *value)
+{
+ if (value == NULL || str_ieq(value, "ser12")) {
+ return HYBBX_BAYCOM_MODE_SER12;
+ }
+ if (str_ieq(value, "ser12*") || str_ieq(value, "ser12_softdcd")) {
+ return HYBBX_BAYCOM_MODE_SER12_SOFTDCD;
+ }
+ if (str_ieq(value, "ser12+") || str_ieq(value, "ser12_inv")) {
+ return HYBBX_BAYCOM_MODE_SER12_INV;
+ }
+ if (str_ieq(value, "ser12hdx") || str_ieq(value, "ser12_hdx") ||
+ str_ieq(value, "hdx")) {
+ return HYBBX_BAYCOM_MODE_SER12HDX;
+ }
+ if (str_ieq(value, "par96")) {
+ return HYBBX_BAYCOM_MODE_PAR96;
+ }
+ if (str_ieq(value, "par96*") || str_ieq(value, "par96_softdcd")) {
+ return HYBBX_BAYCOM_MODE_PAR96_SOFTDCD;
+ }
+ if (str_ieq(value, "epp") || str_ieq(value, "par97") ||
+ str_ieq(value, "baycom_epp")) {
+ return HYBBX_BAYCOM_MODE_EPP;
+ }
+
+ return HYBBX_BAYCOM_MODE_SER12_SOFTDCD;
+}
+
+void hybbx_baycom_config_free(hybbx_baycom_config_t *config)
+{
+ if (config == NULL) {
+ return;
+ }
+
+ free(config->interface);
+ free(config->kernel_module);
+ free(config->device);
+ free(config->mycall);
+ free(config->circuit_host);
+ free(config->link_id);
+ free(config->link_password);
+ free(config->link_role);
+ free(config->frequency_mhz);
+ memset(config, 0, sizeof(*config));
+}
+
+static void apply_mode_defaults(hybbx_baycom_config_t *out)
+{
+ if (out->interface == NULL) {
+ switch (out->mode) {
+ case HYBBX_BAYCOM_MODE_SER12HDX:
+ out->interface = baycom_strdup("bcsh0");
+ break;
+ case HYBBX_BAYCOM_MODE_PAR96:
+ case HYBBX_BAYCOM_MODE_PAR96_SOFTDCD:
+ out->interface = baycom_strdup("bcp0");
+ break;
+ case HYBBX_BAYCOM_MODE_EPP:
+ out->interface = baycom_strdup("bce0");
+ break;
+ case HYBBX_BAYCOM_MODE_SER12:
+ case HYBBX_BAYCOM_MODE_SER12_SOFTDCD:
+ case HYBBX_BAYCOM_MODE_SER12_INV:
+ default:
+ out->interface = baycom_strdup(HYBBX_BAYCOM_DEFAULT_INTERFACE);
+ break;
+ }
+ }
+
+ if (out->kernel_module == NULL) {
+ switch (out->mode) {
+ case HYBBX_BAYCOM_MODE_SER12HDX:
+ out->kernel_module = baycom_strdup("baycom_ser_hdx");
+ break;
+ case HYBBX_BAYCOM_MODE_PAR96:
+ case HYBBX_BAYCOM_MODE_PAR96_SOFTDCD:
+ out->kernel_module = baycom_strdup("baycom_par");
+ break;
+ case HYBBX_BAYCOM_MODE_EPP:
+ out->kernel_module = baycom_strdup("baycom_epp");
+ break;
+ default:
+ out->kernel_module = baycom_strdup("baycom_ser_fdx");
+ break;
+ }
+ }
+
+ if (out->device == NULL) {
+ if (out->backend == HYBBX_BAYCOM_BACKEND_KISS) {
+ out->device = baycom_strdup("/tmp/max25-bcpr/kiss-bc0");
+ } else {
+ out->device = baycom_strdup("/dev/ttyS0");
+ }
+ }
+}
+
+hybbx_result_t hybbx_baycom_config_parse(const char *config,
+ hybbx_baycom_config_t *out)
+{
+ char scratch[128];
+ const char *value;
+
+ if (out == NULL) {
+ return HYBBX_ERR_INVALID;
+ }
+
+ hybbx_baycom_config_free(out);
+
+ if (config == NULL) {
+ config = "";
+ }
+
+ value = find_kv(config, "backend", scratch, sizeof(scratch));
+ out->backend = parse_backend(value);
+
+ value = find_kv(config, "mode", scratch, sizeof(scratch));
+ out->mode = parse_mode(value);
+
+ value = find_kv(config, "interface", scratch, sizeof(scratch));
+ if (value != NULL) {
+ out->interface = baycom_strdup(value);
+ }
+
+ value = find_kv(config, "kernel_module", scratch, sizeof(scratch));
+ if (value != NULL) {
+ out->kernel_module = baycom_strdup(value);
+ }
+
+ value = find_kv(config, "iobase", scratch, sizeof(scratch));
+ out->iobase = value != NULL ? (unsigned)strtoul(value, NULL, 0)
+ : HYBBX_BAYCOM_DEFAULT_IOBASE;
+
+ value = find_kv(config, "irq", scratch, sizeof(scratch));
+ out->irq = value != NULL ? (unsigned)strtoul(value, NULL, 0)
+ : HYBBX_BAYCOM_DEFAULT_IRQ;
+
+ value = find_kv(config, "radio_baud", scratch, sizeof(scratch));
+ if (value == NULL) {
+ value = find_kv(config, "baud", scratch, sizeof(scratch));
+ }
+ out->radio_baud = value != NULL ? (unsigned)strtoul(value, NULL, 0)
+ : HYBBX_BAYCOM_DEFAULT_RADIO_BAUD;
+
+ value = find_kv(config, "kernel_autoload", scratch, sizeof(scratch));
+ out->kernel_autoload = value != NULL ? hybbx_parse_bool(value, 0) : 0;
+
+ value = find_kv(config, "txdelay", scratch, sizeof(scratch));
+ out->txdelay = value != NULL ? (unsigned)strtoul(value, NULL, 0) : 30u;
+
+ value = find_kv(config, "txtail", scratch, sizeof(scratch));
+ out->txtail = value != NULL ? (unsigned)strtoul(value, NULL, 0) : 1u;
+
+ value = find_kv(config, "slot", scratch, sizeof(scratch));
+ if (value == NULL) {
+ value = find_kv(config, "slottime", scratch, sizeof(scratch));
+ }
+ out->slot = value != NULL ? (unsigned)strtoul(value, NULL, 0) : 10u;
+
+ value = find_kv(config, "persist", scratch, sizeof(scratch));
+ if (value == NULL) {
+ value = find_kv(config, "ppersist", scratch, sizeof(scratch));
+ }
+ out->persist = value != NULL ? (unsigned)strtoul(value, NULL, 0) : 128u;
+
+ value = find_kv(config, "full_duplex", scratch, sizeof(scratch));
+ if (value != NULL) {
+ out->full_duplex = hybbx_parse_bool(value, 0);
+ } else {
+ value = find_kv(config, "duplex", scratch, sizeof(scratch));
+ out->full_duplex = value != NULL && str_ieq(value, "full");
+ }
+
+ value = find_kv(config, "device", scratch, sizeof(scratch));
+ if (value != NULL) {
+ out->device = baycom_strdup(value);
+ }
+
+ value = find_kv(config, "serial_baud", scratch, sizeof(scratch));
+ if (value == NULL) {
+ value = find_kv(config, "host_baud", scratch, sizeof(scratch));
+ }
+ out->serial_baud = value != NULL ? (unsigned)strtoul(value, NULL, 0) : 1200u;
+
+ value = find_kv(config, "mycall", scratch, sizeof(scratch));
+ if (value != NULL) {
+ out->mycall = baycom_strdup(value);
+ }
+
+ value = find_kv(config, "circuit_host", scratch, sizeof(scratch));
+ out->circuit_host = baycom_strdup(value != NULL ? value : "127.0.0.1");
+
+ value = find_kv(config, "circuit_port", scratch, sizeof(scratch));
+ out->circuit_port = value != NULL ? (unsigned)strtoul(value, NULL, 0)
+ : HYBBX_CIRCUIT_DEFAULT_PORT;
+
+ value = find_kv(config, "link_id", scratch, sizeof(scratch));
+ out->link_id = baycom_strdup(value != NULL ? value : "baycom-link");
+
+ value = find_kv(config, "link_password", scratch, sizeof(scratch));
+ out->link_password = baycom_strdup(value != NULL ? value : "");
+
+ value = find_kv(config, "link_role", scratch, sizeof(scratch));
+ out->link_role = baycom_strdup(value != NULL ? value : "link");
+
+ value = find_kv(config, "frequency_mhz", scratch, sizeof(scratch));
+ if (value != NULL) {
+ out->frequency_mhz = baycom_strdup(value);
+ }
+
+ apply_mode_defaults(out);
+
+ if (out->backend == HYBBX_BAYCOM_BACKEND_KISS && out->device != NULL) {
+ char *norm = baycom_normalize_kiss_path(out->device);
+
+ if (norm != NULL) {
+ free(out->device);
+ out->device = norm;
+ }
+ }
+
+ if (out->circuit_host == NULL || out->link_id == NULL) {
+ hybbx_baycom_config_free(out);
+ return HYBBX_ERR_NOMEM;
+ }
+
+ return HYBBX_OK;
+}
git clone -b <branch> https://cgit.mode42.com/<repo>.git
git clone -b <branch> git://cgit.mode42.com/<repo>.git

info@mode42.com