Added thermocouple offset calibration and config crc
This commit is contained in:
@@ -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,
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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) {
|
||||||
@@ -302,6 +323,14 @@ int Config::handleActiveTask(unsigned long timeout_ms) {
|
|||||||
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.
|
||||||
// Unsupported tasks must still be completed so the module does not stall.
|
// Unsupported tasks must still be completed so the module does not stall.
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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()
|
||||||
@@ -594,6 +606,10 @@ int Lcd::loop(unsigned long timeout_ms) {
|
|||||||
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;
|
||||||
}
|
}
|
||||||
@@ -668,6 +684,10 @@ int Lcd::loop(unsigned long timeout_ms) {
|
|||||||
this->renderMsgLapCounterLapTime();
|
this->renderMsgLapCounterLapTime();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case screen::MsgCorruptedConfig:
|
||||||
|
this->renderMsgCorruptedConfig();
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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_) {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user