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, DisplayMsgEngineTempHigh,
DisplayMsgLapCounterStart, DisplayMsgLapCounterStart,
DisplayMsgLapCounterLapTime, DisplayMsgLapCounterLapTime,
DisplayMsgCorruptedConfig,
ConfigTrackDetect, ConfigTrackDetect,
ConfigWriteTempTrack, ConfigWriteTempTrack,
ConfigTrackDelete, ConfigTrackDelete,
@@ -46,6 +47,7 @@ enum Type : uint8_t {
ConfigVbatSetLow, ConfigVbatSetLow,
ConfigTengSetLow, ConfigTengSetLow,
ConfigTengSetHigh, ConfigTengSetHigh,
ConfigTengSetOffset,
BatteryCal, BatteryCal,
TelemetrySendLapPacket, TelemetrySendLapPacket,
AllConfigUpdated, AllConfigUpdated,

View File

@@ -16,6 +16,7 @@ struct VehicleConfig {
float vbat_low_ = 0; float vbat_low_ = 0;
float teng_low_ = 0; float teng_low_ = 0;
float teng_high_ = 0; float teng_high_ = 0;
float teng_offset_ = 0;
}; };
struct LatLng { 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_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 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 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) { inline uint16_t trackSlotAddr(uint8_t idx) {
return TRACK_BASE_ADDR + ((idx - 1) * TRACK_SLOT_BYTES); 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 } // namespace eeprom_layout

View File

@@ -133,6 +133,10 @@ Cmd::CommandId Cmd::parseCommandName(const char *input) {
return ThermoSetHigh; return ThermoSetHigh;
} }
if (strcmp(input, "THERMO_SET_OFFSET") == 0) {
return ThermoSetOffset;
}
if (strcmp(input, "DEBUG_UNLOCK") == 0) { if (strcmp(input, "DEBUG_UNLOCK") == 0) {
return DebugUnlock; return DebugUnlock;
} }
@@ -524,6 +528,33 @@ int Cmd::handleThermoSetHigh(unsigned short argc, char* argv[]) {
return result; 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) { int Cmd::handleHelpGlobal(unsigned short argc) {
if (argc != 1) { if (argc != 1) {
#ifdef ERROR #ifdef ERROR
@@ -703,6 +734,9 @@ int Cmd::dispatchCommand(CommandId command, unsigned short argc, char *argv[]) {
case ThermoSetHigh: case ThermoSetHigh:
return this->handleThermoSetHigh(argc, argv); return this->handleThermoSetHigh(argc, argv);
case ThermoSetOffset:
return this->handleThermoSetOffset(argc, argv);
case DebugUnlock: case DebugUnlock:
return this->handleDebugUnlock(argc); return this->handleDebugUnlock(argc);

View File

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

View File

@@ -4,6 +4,7 @@
#include "config.h" #include "config.h"
#include "data/track_store.h" #include "data/track_store.h"
#include "telemetry_common/telemetry_common.h"
#include <math.h> #include <math.h>
#include <string.h> #include <string.h>
@@ -125,6 +126,11 @@ int Config::writeTengHigh(float value) {
return this->writeConfig(); return this->writeConfig();
} }
int Config::writeTengOffset(float value) {
config_.teng_offset_ = value;
return this->writeConfig();
}
Config::Config() : logger_(nullptr), valid_config_(true) {} Config::Config() : logger_(nullptr), valid_config_(true) {}
Config::Config(SystemLogger *logger) : logger_(logger), 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() {} Config::~Config() {}
int Config::readConfig() { int Config::readConfig() {
uint16_t crc;
EEPROM.get(eeprom_layout::CONFIG_ADDR, config_); 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_); configGlobalWrite(config_);
router::sendAll(module::Config, task::AllConfigUpdated);
return 0; return 0;
} }
int Config::writeConfig() { int Config::writeConfig() {
uint16_t crc = crc16_ccitt((uint8_t*)&config_, sizeof(config_));
EEPROM.put(eeprom_layout::CONFIG_ADDR, config_); EEPROM.put(eeprom_layout::CONFIG_ADDR, config_);
EEPROM.put(eeprom_layout::configCRCAddr(), crc);
configGlobalWrite(config_); configGlobalWrite(config_);
#ifdef INFO #ifdef INFO
if (logger_ != nullptr) { if (logger_ != nullptr) {
@@ -301,6 +322,14 @@ int Config::handleActiveTask(unsigned long timeout_ms) {
this->taskComplete(); this->taskComplete();
return result; 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: default:
// Broadcasts such as AllConfigUpdated may be queued back into Config. // Broadcasts such as AllConfigUpdated may be queued back into Config.

View File

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

View File

@@ -378,6 +378,18 @@ int Lcd::renderMsgLapCounterLapTime() {
return 0; 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); } int Lcd::push(const Task &task) { return queue_.push(task); }
Lcd::Lcd() Lcd::Lcd()
@@ -593,6 +605,10 @@ int Lcd::loop(unsigned long timeout_ms) {
case task::DisplayMsgLapCounterLapTime: case task::DisplayMsgLapCounterLapTime:
base_rendered_ = false; base_rendered_ = false;
activateMessage(screen::MsgLapCounterLapTime, next_task.data_); activateMessage(screen::MsgLapCounterLapTime, next_task.data_);
case task::DisplayMsgCorruptedConfig:
base_rendered_ = false;
activateMessage(screen::MsgCorruptedConfig, next_task.data_);
default: default:
break; break;
@@ -667,6 +683,10 @@ int Lcd::loop(unsigned long timeout_ms) {
case screen::MsgLapCounterLapTime: case screen::MsgLapCounterLapTime:
this->renderMsgLapCounterLapTime(); this->renderMsgLapCounterLapTime();
break; break;
case screen::MsgCorruptedConfig:
this->renderMsgCorruptedConfig();
break;
default: default:
break; break;

View File

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

View File

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

View File

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