Added thermocouple offset calibration and config crc

This commit is contained in:
2026-05-20 16:35:30 +02:00
parent 03eb2673f3
commit f63e2711ed
11 changed files with 109 additions and 2 deletions

View File

@@ -38,6 +38,7 @@ enum Type : uint8_t {
DisplayMsgEngineTempHigh,
DisplayMsgLapCounterStart,
DisplayMsgLapCounterLapTime,
DisplayMsgCorruptedConfig,
ConfigTrackDetect,
ConfigWriteTempTrack,
ConfigTrackDelete,
@@ -46,6 +47,7 @@ enum Type : uint8_t {
ConfigVbatSetLow,
ConfigTengSetLow,
ConfigTengSetHigh,
ConfigTengSetOffset,
BatteryCal,
TelemetrySendLapPacket,
AllConfigUpdated,

View File

@@ -16,6 +16,7 @@ struct VehicleConfig {
float vbat_low_ = 0;
float teng_low_ = 0;
float teng_high_ = 0;
float teng_offset_ = 0;
};
struct LatLng {

View File

@@ -15,11 +15,25 @@ static const uint16_t TRACK_SLOT_BYTES = 128;
static const uint16_t TRACK_BASE_ADDR = CONFIG_ADDR + CONFIG_RESERVED_BYTES;
static const uint16_t TRACK_END_ADDR = TRACK_BASE_ADDR + (TRACK_SLOTS * TRACK_SLOT_BYTES);
static const uint16_t FREE_AFTER_TRACKS = TOTAL_BYTES - TRACK_END_ADDR;
static const uint16_t CRC_BASE_OFFSET = 3072;
static const uint16_t CRC_SIZE = sizeof(uint16_t);
static const uint16_t CRC_SLOTS = 9;
static const uint16_t CRC_END_ADDR = CRC_BASE_OFFSET + (CRC_SLOTS * CRC_SIZE);
static_assert(TRACK_END_ADDR <= TOTAL_BYTES, "EEPROM layout exceeds physical storage");
static_assert(TRACK_END_ADDR <= CRC_BASE_OFFSET, "EEPROM layout overlap between tracks and CRC sectors");
static_assert(TRACK_END_ADDR <= TOTAL_BYTES || CRC_END_ADDR <= TOTAL_BYTES, "EEPROM layout exceeds physical storage");
inline uint16_t trackSlotAddr(uint8_t idx) {
return TRACK_BASE_ADDR + ((idx - 1) * TRACK_SLOT_BYTES);
}
inline uint16_t configCRCAddr() {
return CRC_BASE_OFFSET;
}
inline uint16_t trackCRCAddr(uint8_t idx) {
return CRC_BASE_OFFSET + (idx * CRC_SIZE);
}
} // namespace eeprom_layout

View File

@@ -133,6 +133,10 @@ Cmd::CommandId Cmd::parseCommandName(const char *input) {
return ThermoSetHigh;
}
if (strcmp(input, "THERMO_SET_OFFSET") == 0) {
return ThermoSetOffset;
}
if (strcmp(input, "DEBUG_UNLOCK") == 0) {
return DebugUnlock;
}
@@ -524,6 +528,33 @@ int Cmd::handleThermoSetHigh(unsigned short argc, char* argv[]) {
return result;
}
int Cmd::handleThermoSetOffset(unsigned short argc, char* argv[]) {
if (argc != 2) {
#ifdef ERROR
if (logger_ != nullptr) {
logger_->error("THERMO_SET_OFFSET expects 1 argument");
}
#endif
return 1;
}
float offset = strtod(argv[1], nullptr);
uint32_t task_data;
memcpy(&task_data, &offset, sizeof(uint32_t));
#ifdef INFO
if (logger_ != nullptr) {
logger_->info("Setting offset for TENG");
}
#endif
int result = router::send(module::Config, task::ConfigTengSetOffset, task_data);
#ifdef ERROR
if (result != 0 && logger_ != nullptr) {
logger_->error("Failed to queue THERMO_SET_OFFSET config update");
}
#endif
return result;
}
int Cmd::handleHelpGlobal(unsigned short argc) {
if (argc != 1) {
#ifdef ERROR
@@ -703,6 +734,9 @@ int Cmd::dispatchCommand(CommandId command, unsigned short argc, char *argv[]) {
case ThermoSetHigh:
return this->handleThermoSetHigh(argc, argv);
case ThermoSetOffset:
return this->handleThermoSetOffset(argc, argv);
case DebugUnlock:
return this->handleDebugUnlock(argc);

View File

@@ -30,6 +30,7 @@ private:
BatterySetLow,
ThermoSetLow,
ThermoSetHigh,
ThermoSetOffset,
DebugUnlock,
DebugLock,
DbgSendBlankLap,
@@ -67,6 +68,7 @@ private:
int handleBatterySetLow(unsigned short argc, char *argv[]);
int handleThermoSetLow(unsigned short argc, char *argv[]);
int handleThermoSetHigh(unsigned short argc, char *argv[]);
int handleThermoSetOffset(unsigned short argc, char *argv[]);
int handleHelpGlobal(unsigned short argc);
int handleUnknownCommand(unsigned short argc, char *argv[]);
int handleDebugUnlock(unsigned short argc);

View File

@@ -4,6 +4,7 @@
#include "config.h"
#include "data/track_store.h"
#include "telemetry_common/telemetry_common.h"
#include <math.h>
#include <string.h>
@@ -125,6 +126,11 @@ int Config::writeTengHigh(float value) {
return this->writeConfig();
}
int Config::writeTengOffset(float value) {
config_.teng_offset_ = value;
return this->writeConfig();
}
Config::Config() : logger_(nullptr), valid_config_(true) {}
Config::Config(SystemLogger *logger) : logger_(logger), valid_config_(true) {}
@@ -132,13 +138,28 @@ Config::Config(SystemLogger *logger) : logger_(logger), valid_config_(true) {}
Config::~Config() {}
int Config::readConfig() {
uint16_t crc;
EEPROM.get(eeprom_layout::CONFIG_ADDR, config_);
EEPROM.get(eeprom_layout::configCRCAddr(), crc);
int res = crc16_ccitt_check((uint8_t*)&config_, sizeof(config_), crc);
if (res != 0) {
#ifdef ERROR
if (logger_ != nullptr) {
logger_->error("Corrupted config, reset and regenerate config required");
}
#endif
router::send(module::Lcd, task::DisplayMsgCorruptedConfig, 5000);
return 1;
}
configGlobalWrite(config_);
router::sendAll(module::Config, task::AllConfigUpdated);
return 0;
}
int Config::writeConfig() {
uint16_t crc = crc16_ccitt((uint8_t*)&config_, sizeof(config_));
EEPROM.put(eeprom_layout::CONFIG_ADDR, config_);
EEPROM.put(eeprom_layout::configCRCAddr(), crc);
configGlobalWrite(config_);
#ifdef INFO
if (logger_ != nullptr) {
@@ -302,6 +323,14 @@ int Config::handleActiveTask(unsigned long timeout_ms) {
return result;
}
case task::ConfigTengSetOffset: {
float offset_value;
memcpy(&offset_value, &active_task_.data_, sizeof(float));
int result = this->writeTengOffset(offset_value);
this->taskComplete();
return result;
}
default:
// Broadcasts such as AllConfigUpdated may be queued back into Config.
// Unsupported tasks must still be completed so the module does not stall.

View File

@@ -51,6 +51,7 @@ private:
int writeVbatLow(float value);
int writeTengLow(float value);
int writeTengHigh(float value);
int writeTengOffset(float value);
public:
int push(const Task &task) override;

View File

@@ -378,6 +378,18 @@ int Lcd::renderMsgLapCounterLapTime() {
return 0;
}
int Lcd::renderMsgCorruptedConfig() {
if (!base_rendered_) {
this->clear();
display_->setCursor(3, 1);
this->print("CRITICAL ERROR");
display_->setCursor(2, 2);
this->print("CONFIG CORRUPTED");
base_rendered_ = true;
}
return 0;
}
int Lcd::push(const Task &task) { return queue_.push(task); }
Lcd::Lcd()
@@ -594,6 +606,10 @@ int Lcd::loop(unsigned long timeout_ms) {
base_rendered_ = false;
activateMessage(screen::MsgLapCounterLapTime, next_task.data_);
case task::DisplayMsgCorruptedConfig:
base_rendered_ = false;
activateMessage(screen::MsgCorruptedConfig, next_task.data_);
default:
break;
}
@@ -668,6 +684,10 @@ int Lcd::loop(unsigned long timeout_ms) {
this->renderMsgLapCounterLapTime();
break;
case screen::MsgCorruptedConfig:
this->renderMsgCorruptedConfig();
break;
default:
break;
}

View File

@@ -31,6 +31,7 @@ enum LcdScreen : uint8_t {
MsgEngineTempHigh,
MsgLapCounterStart,
MsgLapCounterLapTime,
MsgCorruptedConfig,
};
} // namespace screen
@@ -79,6 +80,7 @@ private:
int renderMsgEngineTempHigh();
int renderMsgLapCounterStart();
int renderMsgLapCounterLapTime();
int renderMsgCorruptedConfig();
public:
int push(const Task &task) override;

View File

@@ -36,6 +36,7 @@ int Thermocouple::loop(unsigned long timeout_ms) {
configGlobalRead(config);
low_ = config.teng_low_;
high_ = config.teng_high_;
offset_ = config.teng_offset_;
break;
}
@@ -46,7 +47,7 @@ int Thermocouple::loop(unsigned long timeout_ms) {
}
if (millis() > last_read_at_ + update_interval_) {
temperature_ = thermocouple_->readCelsius();
temperature_ = thermocouple_->readCelsius() + offset_;
tengGlobalWrite(temperature_);
last_read_at_ = millis();
if (temperature_ > high_) {

View File

@@ -20,6 +20,7 @@ private:
float temperature_;
float low_;
float high_;
float offset_;
unsigned long update_interval_ = 1000;
unsigned long last_read_at_ = 0;
unsigned long warning_sent_at_ = 0;