diff options
| author | info@mode42.com <info@mode42.com> | 2026-08-08 03:54:55 +0000 |
|---|---|---|
| committer | info@mode42.com <info@mode42.com> | 2026-08-08 03:54:55 +0000 |
| commit | 20cb29c2f8c5c87bc590896854a20b1473ceb358 (patch) | |
| tree | 2857f41513a56ad41af97b57362639298aa7f033 /plugins/baycom/baycom_config.c | |
#2
Diffstat (limited to 'plugins/baycom/baycom_config.c')
| -rw-r--r-- | plugins/baycom/baycom_config.c | 395 |
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; +} |
