espilon-source/espilon_bot/components/mod_canbus/canbus_config.c
Eun0us 6d45770d98 epsilon: merge command system into core + add 5 new modules
Move command registry from components/command/ into components/core/.
New modules: mod_canbus, mod_honeypot, mod_fallback, mod_redteam, mod_ota.
Replace mod_proxy with tun_core (multiplexed SOCKS5 tunnel).
Kconfig extended with per-module settings and async worker config.
2026-02-28 20:07:59 +01:00

320 lines
8.3 KiB
C

/*
* canbus_config.c
* NVS-backed persistent config for CAN bus module.
*/
#include "sdkconfig.h"
#ifdef CONFIG_MODULE_CANBUS
#include <stdio.h>
#include <string.h>
#include "esp_log.h"
#include "nvs_flash.h"
#include "nvs.h"
#include "canbus_config.h"
#define TAG "CAN_CFG"
#define NVS_NS "can_cfg"
/* NVS keys */
#define KEY_BITRATE "bitrate"
#define KEY_OSC_MHZ "osc_mhz"
#define KEY_FILTERS "sw_filters"
#define KEY_FILTER_CNT "sw_filt_cnt"
#define KEY_ECUS "ecus"
#define KEY_ECU_CNT "ecu_cnt"
/* ============================================================
* Init
* ============================================================ */
void can_config_init(void)
{
nvs_handle_t h;
esp_err_t err = nvs_open(NVS_NS, NVS_READWRITE, &h);
if (err == ESP_OK) {
nvs_close(h);
ESP_LOGI(TAG, "NVS namespace '%s' ready", NVS_NS);
} else {
ESP_LOGW(TAG, "NVS open failed: %s", esp_err_to_name(err));
}
}
/* ============================================================
* Bitrate
* ============================================================ */
int can_config_get_bitrate(void)
{
nvs_handle_t h;
int32_t val = CONFIG_CANBUS_DEFAULT_BITRATE;
if (nvs_open(NVS_NS, NVS_READONLY, &h) == ESP_OK) {
nvs_get_i32(h, KEY_BITRATE, &val);
nvs_close(h);
}
return (int)val;
}
esp_err_t can_config_set_bitrate(int bitrate)
{
nvs_handle_t h;
esp_err_t err = nvs_open(NVS_NS, NVS_READWRITE, &h);
if (err != ESP_OK) return err;
err = nvs_set_i32(h, KEY_BITRATE, bitrate);
if (err == ESP_OK) err = nvs_commit(h);
nvs_close(h);
return err;
}
/* ============================================================
* Oscillator
* ============================================================ */
uint8_t can_config_get_osc_mhz(void)
{
nvs_handle_t h;
uint8_t val = CONFIG_CANBUS_OSC_MHZ;
if (nvs_open(NVS_NS, NVS_READONLY, &h) == ESP_OK) {
nvs_get_u8(h, KEY_OSC_MHZ, &val);
nvs_close(h);
}
return val;
}
esp_err_t can_config_set_osc_mhz(uint8_t mhz)
{
nvs_handle_t h;
esp_err_t err = nvs_open(NVS_NS, NVS_READWRITE, &h);
if (err != ESP_OK) return err;
err = nvs_set_u8(h, KEY_OSC_MHZ, mhz);
if (err == ESP_OK) err = nvs_commit(h);
nvs_close(h);
return err;
}
/* ============================================================
* Software Filters (stored as blob of uint32_t array)
* ============================================================ */
int can_config_get_filters(uint32_t *ids_out, int max_ids)
{
nvs_handle_t h;
if (nvs_open(NVS_NS, NVS_READONLY, &h) != ESP_OK) return 0;
uint8_t cnt = 0;
nvs_get_u8(h, KEY_FILTER_CNT, &cnt);
if (cnt == 0 || !ids_out) { nvs_close(h); return 0; }
if (cnt > max_ids) cnt = max_ids;
size_t len = cnt * sizeof(uint32_t);
nvs_get_blob(h, KEY_FILTERS, ids_out, &len);
nvs_close(h);
return (int)cnt;
}
static esp_err_t save_filters(nvs_handle_t h, const uint32_t *ids, uint8_t cnt)
{
esp_err_t err = nvs_set_u8(h, KEY_FILTER_CNT, cnt);
if (err != ESP_OK) return err;
if (cnt > 0) {
err = nvs_set_blob(h, KEY_FILTERS, ids, cnt * sizeof(uint32_t));
} else {
nvs_erase_key(h, KEY_FILTERS);
}
if (err == ESP_OK) err = nvs_commit(h);
return err;
}
esp_err_t can_config_add_filter(uint32_t id)
{
nvs_handle_t h;
esp_err_t err = nvs_open(NVS_NS, NVS_READWRITE, &h);
if (err != ESP_OK) return err;
uint32_t ids[CAN_CFG_MAX_SW_FILTERS] = { 0 };
uint8_t cnt = 0;
nvs_get_u8(h, KEY_FILTER_CNT, &cnt);
if (cnt > 0) {
size_t len = cnt * sizeof(uint32_t);
nvs_get_blob(h, KEY_FILTERS, ids, &len);
}
/* Check duplicate */
for (int i = 0; i < cnt; i++) {
if (ids[i] == id) { nvs_close(h); return ESP_OK; }
}
if (cnt >= CAN_CFG_MAX_SW_FILTERS) {
nvs_close(h);
return ESP_ERR_NO_MEM;
}
ids[cnt++] = id;
err = save_filters(h, ids, cnt);
nvs_close(h);
return err;
}
esp_err_t can_config_del_filter(uint32_t id)
{
nvs_handle_t h;
esp_err_t err = nvs_open(NVS_NS, NVS_READWRITE, &h);
if (err != ESP_OK) return err;
uint32_t ids[CAN_CFG_MAX_SW_FILTERS] = { 0 };
uint8_t cnt = 0;
nvs_get_u8(h, KEY_FILTER_CNT, &cnt);
if (cnt > 0) {
size_t len = cnt * sizeof(uint32_t);
nvs_get_blob(h, KEY_FILTERS, ids, &len);
}
/* Find and remove */
bool found = false;
for (int i = 0; i < cnt; i++) {
if (ids[i] == id) {
memmove(&ids[i], &ids[i + 1], (cnt - i - 1) * sizeof(uint32_t));
cnt--;
found = true;
break;
}
}
if (found) {
err = save_filters(h, ids, cnt);
} else {
err = ESP_ERR_NOT_FOUND;
}
nvs_close(h);
return err;
}
esp_err_t can_config_clear_filters(void)
{
nvs_handle_t h;
esp_err_t err = nvs_open(NVS_NS, NVS_READWRITE, &h);
if (err != ESP_OK) return err;
err = save_filters(h, NULL, 0);
nvs_close(h);
return err;
}
/* ============================================================
* ECU IDs (same pattern as filters)
* ============================================================ */
int can_config_get_ecus(uint32_t *ids_out, int max_ids)
{
nvs_handle_t h;
if (nvs_open(NVS_NS, NVS_READONLY, &h) != ESP_OK) return 0;
uint8_t cnt = 0;
nvs_get_u8(h, KEY_ECU_CNT, &cnt);
if (cnt == 0 || !ids_out) { nvs_close(h); return 0; }
if (cnt > max_ids) cnt = max_ids;
size_t len = cnt * sizeof(uint32_t);
nvs_get_blob(h, KEY_ECUS, ids_out, &len);
nvs_close(h);
return (int)cnt;
}
esp_err_t can_config_add_ecu(uint32_t id)
{
nvs_handle_t h;
esp_err_t err = nvs_open(NVS_NS, NVS_READWRITE, &h);
if (err != ESP_OK) return err;
uint32_t ids[CAN_CFG_MAX_ECUS] = { 0 };
uint8_t cnt = 0;
nvs_get_u8(h, KEY_ECU_CNT, &cnt);
if (cnt > 0) {
size_t len = cnt * sizeof(uint32_t);
nvs_get_blob(h, KEY_ECUS, ids, &len);
}
for (int i = 0; i < cnt; i++) {
if (ids[i] == id) { nvs_close(h); return ESP_OK; }
}
if (cnt >= CAN_CFG_MAX_ECUS) {
nvs_close(h);
return ESP_ERR_NO_MEM;
}
ids[cnt++] = id;
err = nvs_set_u8(h, KEY_ECU_CNT, cnt);
if (err == ESP_OK) err = nvs_set_blob(h, KEY_ECUS, ids, cnt * sizeof(uint32_t));
if (err == ESP_OK) err = nvs_commit(h);
nvs_close(h);
return err;
}
esp_err_t can_config_clear_ecus(void)
{
nvs_handle_t h;
esp_err_t err = nvs_open(NVS_NS, NVS_READWRITE, &h);
if (err != ESP_OK) return err;
nvs_set_u8(h, KEY_ECU_CNT, 0);
nvs_erase_key(h, KEY_ECUS);
err = nvs_commit(h);
nvs_close(h);
return err;
}
/* ============================================================
* Reset All
* ============================================================ */
esp_err_t can_config_reset_all(void)
{
nvs_handle_t h;
esp_err_t err = nvs_open(NVS_NS, NVS_READWRITE, &h);
if (err != ESP_OK) return err;
err = nvs_erase_all(h);
if (err == ESP_OK) err = nvs_commit(h);
nvs_close(h);
ESP_LOGI(TAG, "Config reset to defaults");
return err;
}
/* ============================================================
* List (for status responses)
* ============================================================ */
int can_config_list(char *buf, size_t buf_len)
{
int off = 0;
off += snprintf(buf + off, buf_len - off,
"bitrate=%d\nosc_mhz=%u\n",
can_config_get_bitrate(),
can_config_get_osc_mhz());
/* Software filters */
uint32_t fids[CAN_CFG_MAX_SW_FILTERS];
int fcnt = can_config_get_filters(fids, CAN_CFG_MAX_SW_FILTERS);
off += snprintf(buf + off, buf_len - off, "sw_filters=%d:", fcnt);
for (int i = 0; i < fcnt && off < (int)buf_len - 8; i++) {
off += snprintf(buf + off, buf_len - off, " 0x%03lX", (unsigned long)fids[i]);
}
off += snprintf(buf + off, buf_len - off, "\n");
/* Discovered ECUs */
uint32_t eids[CAN_CFG_MAX_ECUS];
int ecnt = can_config_get_ecus(eids, CAN_CFG_MAX_ECUS);
off += snprintf(buf + off, buf_len - off, "ecus=%d:", ecnt);
for (int i = 0; i < ecnt && off < (int)buf_len - 8; i++) {
off += snprintf(buf + off, buf_len - off, " 0x%03lX", (unsigned long)eids[i]);
}
off += snprintf(buf + off, buf_len - off, "\n");
return off;
}
#endif /* CONFIG_MODULE_CANBUS */