diff --git a/src/base/router.cpp b/src/base/router.cpp index cfccb64..7338d1e 100644 --- a/src/base/router.cpp +++ b/src/base/router.cpp @@ -5,22 +5,34 @@ #include "router.h" namespace router { - int send(const Task& task) { - if (task.target >= MOD_COUNT) { - return 1; - } +int send(const Task &task) { + if (task.target == MOD_ALL) { + for (size_t i = 0; i < MOD_COUNT; i++) { - module_base* mod = modules[task.target]; + module_base *mod = modules[i]; - if (mod == nullptr) { - return 1; - } + if (mod == nullptr) { + continue; + } - return mod->push(task); + return mod->push(task); } + } + if (task.target >= MOD_COUNT) { + return 1; + } - int send(module_id target, task_type type, uint32_t data) { - Task t{target, type, data}; - return send(t); - } -} \ No newline at end of file + module_base *mod = modules[task.target]; + + if (mod == nullptr) { + return 1; + } + + return mod->push(task); +} + +int send(module_id target, task_type type, uint32_t data) { + Task t{target, type, data}; + return send(t); +} +} // namespace router \ No newline at end of file diff --git a/src/base/task.h b/src/base/task.h index c420013..c8bf956 100644 --- a/src/base/task.h +++ b/src/base/task.h @@ -10,8 +10,10 @@ enum module_id : uint8_t { MOD_CFG, MOD_GPS, MOD_LCD, + MOD_BAT, MOD_COUNT, - MOD_NULL + MOD_NULL, + MOD_ALL, }; enum task_type : uint8_t { @@ -25,6 +27,9 @@ enum task_type : uint8_t { TASK_CONFIG_WRITE_TEMP_TRACK, TASK_CONFIG_TRACK_DELETE, TASK_CONFIG_CFG_RESET, + TASK_CONFIG_VBAT_CAL_SET, + TASK_BATTERY_CAL, + TASK_ALL_CONFIG_UPDATED, }; struct Task { diff --git a/src/custom_types.h b/src/custom_types.h index 282eb8c..c4ab8ab 100644 --- a/src/custom_types.h +++ b/src/custom_types.h @@ -11,6 +11,7 @@ struct vehicle_config{ bool auto_detect_track = true; uint8_t track_fallback = 0; bool track_slot_occupied[8] = {false}; + double vbat_calibration = 0; }; struct lat_lng { diff --git a/src/data/general_store.cpp b/src/data/general_store.cpp new file mode 100644 index 0000000..8b6c92f --- /dev/null +++ b/src/data/general_store.cpp @@ -0,0 +1,14 @@ +// Copyright (C) 2026 Hector van der Aa +// Copyright (C) 2026 Association Exergie +// SPDX-License-Identifier: GPL-3.0-or-later +#include "general_store.h" + + volatile double vbat_global = 0; + + void vbat_global_read(double& out) { + out = vbat_global; + } + + void vbat_global_write(const double& in) { + vbat_global = in; + } \ No newline at end of file diff --git a/src/data/general_store.h b/src/data/general_store.h new file mode 100644 index 0000000..c34a50c --- /dev/null +++ b/src/data/general_store.h @@ -0,0 +1,9 @@ +// Copyright (C) 2026 Hector van der Aa +// Copyright (C) 2026 Association Exergie +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +extern volatile double vbat_global; + +void vbat_global_read(double& out); +void vbat_global_write(const double& in); \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 5fa8419..f27f51f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -13,6 +13,7 @@ #include "base/modules.h" #include "base/module_base.h" #include "base/router.h" +#include "modules/battery/battery.h" @@ -22,6 +23,7 @@ lcd *driver_display = new lcd(logger_output); gps *gps_module = new gps(&Serial2, logger_output); config *system_config = new config(logger_output); cmd *command_handler = new cmd(&Serial, logger_output); +battery *battery_handler = new battery(logger_output); void setup() { @@ -31,6 +33,7 @@ void setup() { modules[MOD_GPS] = gps_module; modules[MOD_CFG] = system_config; modules[MOD_CMD] = command_handler; + modules[MOD_BAT] = battery_handler; driver_display->init(); driver_display->print_message("Starting Initialization"); @@ -57,6 +60,12 @@ void setup() { delay(1000); driver_display->print_message("GPS Init Complete"); delay(1000); + + driver_display->print_message("Bat Init..."); + battery_handler->init(); + delay(1000); + driver_display->print_message("Bat Init Complete"); + delay(1000); router::send(MOD_LCD, TASK_DISPLAY_DRIVER_PRIMARY); } @@ -65,4 +74,5 @@ void loop() { driver_display->loop(); command_handler->parse_task(); system_config->loop(); + battery_handler->loop(); } diff --git a/src/modules/battery/battery.cpp b/src/modules/battery/battery.cpp index 3a9ef37..cd0c720 100644 --- a/src/modules/battery/battery.cpp +++ b/src/modules/battery/battery.cpp @@ -3,12 +3,70 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "battery.h" +#include "base/router.h" +#include "data/config_store.h" +#include "data/general_store.h" + +int battery::calibrate(const Task &task) { + double actual_voltage; + memcpy(&actual_voltage, &task.data, sizeof(double)); + int adc_read = analogRead(VBAT_PIN); + double cal_factor = actual_voltage / adc_read; + uint32_t output_val; + memcpy(&output_val, &cal_factor, sizeof(uint32_t)); + router::send(MOD_CFG, TASK_CONFIG_VBAT_CAL_SET, output_val); + return 0; +} int battery::push(const Task &task) { return _queue.push(task); } battery::battery() : _logger(nullptr) {} -battery::battery(system_logger *logger) - : _logger(logger) {} +battery::battery(system_logger *logger) : _logger(logger) {} -battery::~battery() {} \ No newline at end of file +battery::~battery() {} + +int battery::init() { + pinMode(VBAT_PIN, INPUT); + vehicle_config config; + config_global_read(config); + _cal = config.vbat_calibration; +} + +int battery::loop(unsigned long timeout_ms) { + if (millis() > _last_read + _update_interval) { + int adc_read = analogRead(VBAT_PIN); + _vbat = _cal * adc_read; + + vbat_global_write(_vbat); + } + Task active_task; + int res = _queue.pop(active_task); + if (res == 0) { + if (active_task.target == MOD_BAT) { + + switch (active_task.type) { + case TASK_BATTERY_CAL: + this->calibrate(active_task); + break; + + default: + break; + } + } else if (active_task.target == MOD_ALL) { + switch (active_task.type) + { + case TASK_ALL_CONFIG_UPDATED: { + vehicle_config config; + config_global_read(config); + _cal = config.vbat_calibration; + break; + } + + default: + break; + } + } + } + return 0; +} \ No newline at end of file diff --git a/src/modules/battery/battery.h b/src/modules/battery/battery.h index c431b43..688c9a3 100644 --- a/src/modules/battery/battery.h +++ b/src/modules/battery/battery.h @@ -2,8 +2,10 @@ // Copyright (C) 2026 Association Exergie // SPDX-License-Identifier: GPL-3.0-or-later #pragma once - +#define VBAT_PIN A3 #include "base/module_base.h" +#include "base/ring_buffer.h" +#include "custom_types.h" #include "modules/logger/system_logger.h" #include @@ -12,10 +14,17 @@ class battery : public module_base { private: system_logger *_logger; ring_buffer _queue; + double _vbat = 0; + double _cal = 0; + unsigned long _update_interval = 1000; + unsigned long _last_read = 0; + int calibrate(const Task& task); public: int push(const Task &task) override; battery(); battery(system_logger *logger); ~battery(); + int init(); + int loop(unsigned long timeout_ms = 500); }; \ No newline at end of file diff --git a/src/modules/cmd/cmd.cpp b/src/modules/cmd/cmd.cpp index 245e740..3b19aa2 100644 --- a/src/modules/cmd/cmd.cpp +++ b/src/modules/cmd/cmd.cpp @@ -7,6 +7,7 @@ #include #include "data/track_store.h" #include "data/config_store.h" +#include "data/general_store.h" #include "base/router.h" char *cmd::trim_arg(char *input) { @@ -107,6 +108,14 @@ cmd::command_id cmd::parse_command_name(const char *input) { return CMD_DISPLAY_DRIVER_PRIMARY; } + if (strcmp(input, "BATTERY_CAL") == 0) { + return CMD_BATTERY_CAL; + } + + if (strcmp(input, "BATTERY_PRINT_VBAT") == 0) { + return CMD_BATTERY_PRINT_VBAT; + } + return CMD_UNKNOWN; } @@ -362,6 +371,46 @@ int cmd::handle_display_driver_primary(unsigned short argc) { return router::send(MOD_LCD, TASK_DISPLAY_DRIVER_PRIMARY); } +int cmd::handle_battery_cal(unsigned short argc, char *argv[]) { + if (argc != 2) { +#ifdef ERROR + if (_logger != nullptr) { + _logger->error("BATTERY_CAL expects 1 argument"); + } +#endif + return 1; + } + double vbat = strtod(argv[1], nullptr); + uint32_t task_data; + memcpy(&task_data, &vbat, sizeof(uint32_t)); +#ifdef INFO + if (_logger != nullptr) { + _logger->info("Calibrating VBAT"); + } +#endif + router::send(MOD_BAT, TASK_BATTERY_CAL, task_data); + return 0; +} + +int cmd::handle_battery_print_vbat(unsigned short argc) { + if (argc != 1) { +#ifdef ERROR + if (_logger != nullptr) { + _logger->error("BATTERY_PRINT_VBAT expects no arguments"); + } +#endif + return 1; + } + +#ifdef INFO + double vbat; + vbat_global_read(vbat); + if (_logger != nullptr) { + _logger->info("VBAT: " + String(vbat)); + } +#endif +} + int cmd::handle_unknown_command(unsigned short argc, char *argv[]) { #ifdef ERROR if (_logger != nullptr) { @@ -403,6 +452,12 @@ int cmd::dispatch_command(command_id command, unsigned short argc, char *argv[]) case CMD_DISPLAY_DRIVER_PRIMARY: return this->handle_display_driver_primary(argc); + + case CMD_BATTERY_CAL: + return this->handle_battery_cal(argc, argv); + + case CMD_BATTERY_PRINT_VBAT: + return this->handle_battery_print_vbat(argc); case CMD_UNKNOWN: default: diff --git a/src/modules/cmd/cmd.h b/src/modules/cmd/cmd.h index b7b044a..f2d3134 100644 --- a/src/modules/cmd/cmd.h +++ b/src/modules/cmd/cmd.h @@ -25,6 +25,8 @@ private: CMD_TRACK_AUTODETECT, CMD_DISPLAY_GPS_DEBUG, CMD_DISPLAY_DRIVER_PRIMARY, + CMD_BATTERY_CAL, + CMD_BATTERY_PRINT_VBAT, }; HardwareSerial *_data_stream; @@ -53,6 +55,8 @@ private: int handle_track_autodetect_command(unsigned short argc); int handle_display_gps_debug(unsigned short argc); int handle_display_driver_primary(unsigned short argc); + int handle_battery_cal(unsigned short argc, char *argv[]); + int handle_battery_print_vbat(unsigned short argc); int handle_unknown_command(unsigned short argc, char *argv[]); public: diff --git a/src/modules/config/config.cpp b/src/modules/config/config.cpp index 7f23083..3cb0e87 100644 --- a/src/modules/config/config.cpp +++ b/src/modules/config/config.cpp @@ -8,9 +8,7 @@ #include #include -int config::push(const Task &task) { - return _queue.push(task); -} +int config::push(const Task &task) { return _queue.push(task); } int config::task_complete() { _task_memory_stale = true; @@ -18,32 +16,32 @@ int config::task_complete() { return 0; } -int config::write_track(const track_data& in) { +int config::write_track(const track_data &in) { track_data copy = in; copy.magic = CONFIG_MAGIC; if (copy.id < 1 || copy.id > 8) { - #ifdef ERROR - if (_logger != nullptr) { +#ifdef ERROR + if (_logger != nullptr) { _logger->error("Cannot write track data with out of range id, aborting"); } - #endif +#endif return 1; } EEPROM.put(eeprom_layout::track_slot_addr(copy.id), copy); _config.track_slot_occupied[copy.id - 1] = true; this->write_cfg(); - #ifdef INFO - if (_logger !=nullptr) { +#ifdef INFO + if (_logger != nullptr) { _logger->info("Succesfully wrote new track into slot " + String(copy.id)); } - #endif - return 0; +#endif + return 0; } int config::write_track_from_temp() { - track_data new_track; - track_temp_global_read(new_track); - return this->write_track(new_track); + track_data new_track; + track_temp_global_read(new_track); + return this->write_track(new_track); } int config::delete_track(unsigned short idx) { @@ -101,6 +99,11 @@ int config::reset_cfg() { return this->write_cfg(); } +int config::write_vbat_cal(double val) { + _config.vbat_calibration = val; + return this->write_cfg(); +} + config::config() : _logger(nullptr), _valid_config(true) {} config::config(system_logger *logger) : _logger(logger), _valid_config(true) {} @@ -116,11 +119,12 @@ int config::read_cfg() { int config::write_cfg() { EEPROM.put(eeprom_layout::config_addr, _config); config_global_write(_config); - #ifdef INFO +#ifdef INFO if (_logger != nullptr) { _logger->info("Config updated and saved to EEPROM"); } - #endif +#endif + router::send(MOD_ALL, TASK_ALL_CONFIG_UPDATED); return 0; } @@ -215,7 +219,6 @@ int config::handle_active_task(unsigned long timeout_ms) { } this->task_complete(); return 0; - } case TASK_CONFIG_WRITE_TEMP_TRACK: { @@ -236,6 +239,13 @@ int config::handle_active_task(unsigned long timeout_ms) { return res; } + case TASK_CONFIG_VBAT_CAL_SET: { + double cal_value; + memcpy(&cal_value, &_active_task.data, sizeof(double)); + int res = this->write_vbat_cal(cal_value); + this->task_complete(); + } + default: break; } diff --git a/src/modules/config/config.h b/src/modules/config/config.h index ea1793f..db383fe 100644 --- a/src/modules/config/config.h +++ b/src/modules/config/config.h @@ -47,6 +47,7 @@ private: int write_track_from_temp(); int delete_track(unsigned short idx); int reset_cfg(); + int write_vbat_cal(double val); public: int push(const Task &task) override;