reworked Settings-handling and tuned up CLI

This commit is contained in:
2025-12-05 15:43:36 +01:00
parent c889eec818
commit 0cdc609df5
9 changed files with 413 additions and 264 deletions

View File

@@ -1,7 +1,7 @@
#include "MotorController.h" #include "MotorController.h"
// Default-Konfiguration // Default-Konfiguration
const MotorConfig defaultConfig = { const MotorConfig_t defaultConfig = {
.minPWM = 0, .minPWM = 0,
.maxPWM = 255, .maxPWM = 255,
.inverted = true, .inverted = true,
@@ -9,7 +9,7 @@ const MotorConfig defaultConfig = {
.lookupTable = {0, 10, 20, 30, 40, 50, 60, 70, 80, 100} // 0..100% Kennlinie .lookupTable = {0, 10, 20, 30, 40, 50, 60, 70, 80, 100} // 0..100% Kennlinie
}; };
MotorController::MotorController(const MotorSignals &signals) MotorController::MotorController(const MotorSignals_t &signals)
: signals_(signals) : signals_(signals)
{ {
loadDefaults(); loadDefaults();
@@ -29,7 +29,7 @@ MotorController::MotorController(const MotorSignals &signals)
lastSpeedPercent = 0; lastSpeedPercent = 0;
} }
void MotorController::setSignals(const MotorSignals &signals) void MotorController::setSignals(const MotorSignals_t &signals)
{ {
signals_ = signals; signals_ = signals;
@@ -59,12 +59,12 @@ void MotorController::loadDefaults()
} }
} }
MotorConfig MotorController::getConfig() const MotorConfig_t MotorController::getConfig() const
{ {
return config; return config;
} }
void MotorController::setConfig(const MotorConfig &newConfig) void MotorController::setConfig(const MotorConfig_t &newConfig)
{ {
config = newConfig; config = newConfig;
@@ -105,7 +105,7 @@ void MotorController::maintain()
lastSpeedPercent = adjustedSpeed; lastSpeedPercent = adjustedSpeed;
// 3) Lookup-Interpolation von Prozent -> LUT-Prozent // 3) Lookup-Interpolation von Prozent -> LUT-Prozent
const int16_t n = MotorConfig::lookupTableSize; const int16_t n = MotorConfig_t::lookupTableSize;
float pos = (adjustedSpeed / 100.0f) * (n - 1); // 0..(n-1) als float float pos = (adjustedSpeed / 100.0f) * (n - 1); // 0..(n-1) als float
int16_t lowerIndex = (int16_t)pos; int16_t lowerIndex = (int16_t)pos;
if (lowerIndex < 0) if (lowerIndex < 0)

View File

@@ -3,7 +3,7 @@
#include <Arduino.h> #include <Arduino.h>
struct MotorConfig typedef struct MotorConfig
{ {
uint8_t minPWM; uint8_t minPWM;
uint8_t maxPWM; uint8_t maxPWM;
@@ -11,7 +11,7 @@ struct MotorConfig
int16_t responseSpeed; // Prozent pro Sekunde int16_t responseSpeed; // Prozent pro Sekunde
static const int16_t lookupTableSize = 10; static const int16_t lookupTableSize = 10;
uint8_t lookupTable[lookupTableSize]; uint8_t lookupTable[lookupTableSize];
}; }MotorConfig_t;
typedef struct MotorSignals typedef struct MotorSignals
{ {
@@ -28,14 +28,14 @@ typedef struct MotorSignals
// Debug // Debug
bool *debugFlag; // globales Debug-Flag bool *debugFlag; // globales Debug-Flag
} MotorSignals; } MotorSignals_t;
class MotorController class MotorController
{ {
public: public:
explicit MotorController(const MotorSignals &signals); explicit MotorController(const MotorSignals_t &signals);
void setSignals(const MotorSignals &signals); void setSignals(const MotorSignals_t &signals);
// zyklisch in loop() aufrufen // zyklisch in loop() aufrufen
void maintain(); void maintain();
@@ -43,13 +43,13 @@ public:
// Hard Stop // Hard Stop
void stopMotor(); void stopMotor();
MotorConfig getConfig() const; MotorConfig_t getConfig() const;
void setConfig(const MotorConfig &newConfig); void setConfig(const MotorConfig_t &newConfig);
void loadDefaults(); void loadDefaults();
private: private:
MotorSignals signals_; MotorSignals_t signals_;
MotorConfig config; MotorConfig_t config;
// interner Dynamik-State // interner Dynamik-State
int16_t smoothedPromille = 0; // 0..1000 int16_t smoothedPromille = 0; // 0..1000

View File

@@ -3,7 +3,7 @@
// sinnvolle Defaults grob um den real genutzen Bereich // sinnvolle Defaults grob um den real genutzen Bereich
// nicht gedrückt ~425, gedrückt ~227 // nicht gedrückt ~425, gedrückt ~227
static const PedalConfig defaultConfig = { static const PedalConfig_t defaultConfig = {
.minRaw = 230, // grob gedrückt .minRaw = 230, // grob gedrückt
.maxRaw = 420, // grob nicht gedrückt .maxRaw = 420, // grob nicht gedrückt
.calibrated = false, .calibrated = false,
@@ -23,10 +23,8 @@ static const uint8_t MIN_FS = 1; // Filterstärke min.
static const uint8_t MAX_FS = 32; // Filterstärke max. static const uint8_t MAX_FS = 32; // Filterstärke max.
static const uint8_t DEFAULT_FS = 3; // Standard-Filterstärke static const uint8_t DEFAULT_FS = 3; // Standard-Filterstärke
PedalController::PedalController(const PedalSignals &signals, PedalController::PedalController(const PedalSignals_t &signals)
uint8_t digitalNotPressedLevel_)
: signals_(signals), : signals_(signals),
digitalNotPressedLevel(digitalNotPressedLevel_ ? 1 : 0),
config(), config(),
filteredValue(-1), filteredValue(-1),
lastPedalPercent(0), lastPedalPercent(0),
@@ -46,12 +44,6 @@ PedalController::PedalController(const PedalSignals &signals,
step3NearReleased(false), step3NearReleased(false),
step4NearPressed(false) step4NearPressed(false)
{ {
// Digital-Pin als INPUT konfigurieren, falls vorhanden
if (signals_.digitalPin >= 0)
{
pinMode(signals_.digitalPin, INPUT);
}
loadDefaults(); loadDefaults();
} }
@@ -461,20 +453,6 @@ int16_t PedalController::getPedal()
void PedalController::maintain() void PedalController::maintain()
{ {
int16_t raw = applySmoothing(readRaw()); int16_t raw = applySmoothing(readRaw());
// Outputs befüllen
if (signals_.rawValue)
*signals_.rawValue = raw;
// digitaler Eingang (falls vorhanden)
if (signals_.digitalState)
{
if (signals_.digitalPin >= 0)
*signals_.digitalState = digitalRead(signals_.digitalPin);
else
*signals_.digitalState = -1;
}
int16_t percent = mapRawToPercent(raw); int16_t percent = mapRawToPercent(raw);
lastPedalPercent = percent; lastPedalPercent = percent;
@@ -490,12 +468,12 @@ void PedalController::maintain()
} }
} }
PedalConfig PedalController::getConfig() const PedalConfig_t PedalController::getConfig() const
{ {
return config; return config;
} }
void PedalController::setConfig(const PedalConfig &newConfig) void PedalController::setConfig(const PedalConfig_t &newConfig)
{ {
config = newConfig; config = newConfig;
@@ -543,14 +521,9 @@ void PedalController::loadDefaults()
step4NearPressed = false; step4NearPressed = false;
} }
void PedalController::setSignals(const PedalSignals &signals) void PedalController::setSignals(const PedalSignals_t &signals)
{ {
signals_ = signals; signals_ = signals;
if (signals_.digitalPin >= 0)
{
pinMode(signals_.digitalPin, INPUT);
}
} }
void PedalController::printStatus(int16_t raw) void PedalController::printStatus(int16_t raw)
@@ -571,17 +544,6 @@ void PedalController::printStatus(int16_t raw)
Serial.print(raw); Serial.print(raw);
Serial.print(" Smooth="); Serial.print(" Smooth=");
Serial.print(filteredValue); Serial.print(filteredValue);
Serial.print(" DO-State=");
if (signals_.digitalPin >= 0)
{
Serial.print(digitalRead(signals_.digitalPin));
}
else
{
Serial.print("N/A");
}
Serial.print(" firstRel="); Serial.print(" firstRel=");
Serial.print(firstReleased); Serial.print(firstReleased);
Serial.print(" firstPress="); Serial.print(" firstPress=");

View File

@@ -12,37 +12,34 @@ enum CalibrationState
ERROR ERROR
}; };
struct PedalConfig typedef struct PedalConfig
{ {
int16_t minRaw; int16_t minRaw;
int16_t maxRaw; int16_t maxRaw;
bool calibrated; bool calibrated;
uint8_t filterStrength; uint8_t filterStrength;
}; }PedalConfig_t;
typedef struct PedalSignals typedef struct PedalSignals
{ {
// Pins (by value) // Pins (by value)
int16_t analogPin; // ADC-Pin int16_t analogPin; // ADC-Pin
int16_t digitalPin; // -1 falls unbenutzt
// Eingänge // Eingänge
bool *debugFlag; // globales Debug-Flag bool *debugFlag; // globales Debug-Flag
// Ausgänge // Ausgänge
int16_t *pedalPercent; // 0..100% int16_t *pedalPercent; // 0..100%
int16_t *rawValue; // gefilterter Rawwert
bool *calibrated; // Status bool *calibrated; // Status
int16_t *digitalState; // DO-Status oder -1
} PedalSignals; } PedalSignals_t;
class PedalController class PedalController
{ {
public: public:
PedalController(const PedalSignals &signals, PedalController(const PedalSignals_t &signals);
uint8_t digitalNotPressedLevel = LOW);
void setSignals(const PedalSignals &signals); void setSignals(const PedalSignals_t &signals);
CalibrationState autoCalibrate(bool reset); CalibrationState autoCalibrate(bool reset);
CalibrationState getStatus() const; CalibrationState getStatus() const;
@@ -50,15 +47,14 @@ public:
int16_t getPedal(); // alte API (blocking) int16_t getPedal(); // alte API (blocking)
void maintain(); // neue Non-Blocking-API void maintain(); // neue Non-Blocking-API
PedalConfig getConfig() const; PedalConfig_t getConfig() const;
void setConfig(const PedalConfig &cfg); void setConfig(const PedalConfig_t &cfg);
void loadDefaults(); void loadDefaults();
private: private:
PedalSignals signals_; PedalSignals_t signals_;
uint8_t digitalNotPressedLevel; // nur Debug / Interpretation
PedalConfig config; PedalConfig_t config;
int32_t filteredValue; int32_t filteredValue;
int16_t lastPedalPercent; int16_t lastPedalPercent;

View File

@@ -1,9 +1,11 @@
#include <Arduino.h> #include <Arduino.h>
#include <EEPROM.h>
#include "SerialController.h" #include "SerialController.h"
SerialController::SerialController(const SerialSignals &signals) SerialController::SerialController(const SerialSignals_t &signals)
: signals_(signals) : signals_(signals)
{ {
cmdIndex_ = 0;
} }
void SerialController::maintain() void SerialController::maintain()
@@ -11,145 +13,309 @@ void SerialController::maintain()
while (Serial.available() > 0) while (Serial.available() > 0)
{ {
char c = Serial.read(); char c = Serial.read();
handleCommand(c);
// ESC = komplette Zeile verwerfen
if (c == 0x1B) // ESC
{
cmdIndex_ = 0;
Serial.println(); // neue Zeile für frische Eingabe
return;
}
// Backspace oder DEL
if (c == 0x08 || c == 0x7F)
{
if (cmdIndex_ > 0)
{
cmdIndex_--;
cmdBuffer_[cmdIndex_] = '\0';
// Visuelles Löschen im Terminal
Serial.print("\b \b");
}
return;
}
// Zeilenende
if (c == '\r')
{
return;
}
if (c == '\n')
{
Serial.println(); // Prompt / neue Eingabe
if (cmdIndex_ > 0)
{
cmdBuffer_[cmdIndex_] = '\0';
handleCommand(cmdBuffer_);
cmdIndex_ = 0;
}
Serial.print(F(">"));
return;
}
// Printable ASCII?
if (c >= 32 && c <= 126)
{
if (cmdIndex_ < (CMD_BUFFER_SIZE - 1))
{
cmdBuffer_[cmdIndex_++] = c;
Serial.print(c); // Zeichen lokal anzeigen
}
else
{
// Buffer voll → ignorieren oder Fehlbeep
Serial.print('\a'); // optional Terminal-Bell
}
}
} }
} }
void SerialController::handleCommand(char c) void SerialController::handleCommand(char *line)
{ {
switch (c) // Leading Spaces entfernen
while (*line == ' ' || *line == '\t')
++line;
if (*line == '\0')
return; // leere Zeile
// Alles in UPPERCASE wandeln
for (char *p = line; *p != '\0'; ++p)
{
if (*p >= 'a' && *p <= 'z')
{
*p = *p - 'a' + 'A';
}
}
// Erstes Token (CMD) isolieren
char *p = line;
while (*p != '\0' && *p != ' ' && *p != '\t')
++p;
char *cmd = line;
char *arg1 = nullptr;
char *arg2 = nullptr;
if (*p != '\0')
{
*p++ = '\0'; // CMD terminieren
// ARG1
while (*p == ' ' || *p == '\t')
++p;
if (*p != '\0')
{
arg1 = p;
while (*p != '\0' && *p != ' ' && *p != '\t')
++p;
if (*p != '\0')
{
*p++ = '\0';
// ARG2
while (*p == ' ' || *p == '\t')
++p;
if (*p != '\0')
{
arg2 = p;
while (*p != '\0' && *p != ' ' && *p != '\t')
++p;
*p = '\0';
}
}
}
}
// === Einfache / alte Single-Char-Kommandos per strcmp ===
// Help: HELP
if (strcmp(cmd, "HELP") == 0)
{ {
case 'h':
printHelp(); printHelp();
break; return;
}
case 'd': // Debug toggeln // Debug toggle:
if (strcmp(cmd, "DEBUG") == 0)
{
if (signals_.debugFlag) if (signals_.debugFlag)
{ {
*signals_.debugFlag = !*signals_.debugFlag; *signals_.debugFlag = !*signals_.debugFlag;
Serial.print("Debug: "); Serial.print(F("Debug: "));
Serial.println(*signals_.debugFlag ? "ON" : "OFF"); Serial.println(*signals_.debugFlag ? F("ON") : F("OFF"));
}
return;
} }
break;
case '+': // Geschwindigkeit +5% // Serielles Save/Load/Defaults:
if (signals_.targetSpeedPercent) if (strcmp(cmd, "SAVE") == 0)
{ {
if (signals_.serialControlEnabled) if (signals_.requestSaveEEPROM)
*signals_.serialControlEnabled = true;
int16_t v = *signals_.targetSpeedPercent;
v = constrain(v + 5, (int16_t)0, (int16_t)100);
*signals_.targetSpeedPercent = v;
Serial.print("Target +: ");
Serial.print(v);
Serial.println("%");
}
break;
case '-': // Geschwindigkeit -5%
if (signals_.targetSpeedPercent)
{ {
if (signals_.serialControlEnabled) *signals_.requestSaveEEPROM = true;
*signals_.serialControlEnabled = true; Serial.println(F("Request: Save settings to EEPROM."));
}
int16_t v = *signals_.targetSpeedPercent; return;
v = constrain(v - 5, (int16_t)0, (int16_t)100);
*signals_.targetSpeedPercent = v;
Serial.print("Target -: ");
Serial.print(v);
Serial.println("%");
} }
break;
// direkte 0100%-Vorgabe in 10%-Schritten if (strcmp(cmd, "LOAD") == 0)
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (signals_.targetSpeedPercent)
{ {
if (signals_.serialControlEnabled) if (signals_.requestLoadEEPROM)
*signals_.serialControlEnabled = true; {
*signals_.requestLoadEEPROM = true;
int16_t v = (c - '0') * 10; Serial.println(F("Request: Load settings from EEPROM."));
v = constrain(v, (int16_t)0, (int16_t)100); }
*signals_.targetSpeedPercent = v; return;
Serial.print("Target set: ");
Serial.print(v);
Serial.println("%");
} }
break;
case 'x': // Serielle Steuerung stoppen & Motor freigeben if (strcmp(cmd, "DEFAULTS") == 0)
{
if (signals_.requestLoadDefaults)
{
*signals_.requestLoadDefaults = true;
Serial.println(F("Request: Load defaults."));
}
return;
}
// Auto-Cal:
if (strcmp(cmd, "CAL") == 0)
{
if (signals_.requestAutoCal)
{
*signals_.requestAutoCal = true;
Serial.println(F("Request: Auto-Calibration."));
}
return;
}
// Serial Control stoppen: X
if (strcmp(cmd, "X") == 0)
{
if (signals_.serialControlEnabled) if (signals_.serialControlEnabled)
*signals_.serialControlEnabled = false; *signals_.serialControlEnabled = false;
if (signals_.targetSpeedPercent) if (signals_.targetSpeedPercent)
*signals_.targetSpeedPercent = 0; *signals_.targetSpeedPercent = 0;
Serial.println("Serial control disabled, target=0%."); Serial.println(F("Serial control disabled, target=0%."));
break; return;
}
case 'c': // Auto-Cal anfordern if (strcmp(cmd, "SPEED") == 0)
if (signals_.requestAutoCal)
{ {
*signals_.requestAutoCal = true; if (!arg1)
Serial.println("Request: Auto-Calibration.");
}
break;
case 's': // Save EEPROM
if (signals_.requestSaveEEPROM)
{ {
*signals_.requestSaveEEPROM = true; Serial.println(F("ERR: SPEED requires: SPEED <0..10>"));
Serial.println("Request: Save settings to EEPROM."); return;
} }
break;
case 'l': // Load EEPROM int step = atoi(arg1); // 0..10
if (signals_.requestLoadEEPROM) int16_t v = (int16_t)(step * 10);
v = constrain(v, (int16_t)0, (int16_t)100);
if (signals_.targetSpeedPercent)
{ {
*signals_.requestLoadEEPROM = true; if (signals_.serialControlEnabled)
Serial.println("Request: Load settings from EEPROM."); *signals_.serialControlEnabled = true;
}
break;
case 'r': // Defaults laden *signals_.targetSpeedPercent = v;
if (signals_.requestLoadDefaults) snprintf_P(printBuffer_, sizeof(printBuffer_), PSTR("Target speed set: %d%%"), v);
Serial.println(printBuffer_);
}
return;
}
// === EEPROM-Kommandos ===
if (strcmp(cmd, "EW") == 0)
{ {
*signals_.requestLoadDefaults = true; // EW <addr> <value>
Serial.println("Request: Load defaults."); if (!arg1 || !arg2)
{
Serial.println(F("ERR: EW requires: EW <addr> <value>"));
return;
} }
break;
default: int addr = atoi(arg1);
// Optional: unerkanntes Kommando anzeigen int value = atoi(arg2);
// Serial.print("Unknown command: "); cmdEepromWrite(addr, value);
// Serial.println(c); return;
break;
} }
if (strcmp(cmd, "ER") == 0)
{
// ER <addr>
if (!arg1)
{
Serial.println(F("ERR: ER requires: ER <addr>"));
return;
}
int addr = atoi(arg1);
cmdEepromRead(addr);
return;
}
// === Fallback ===
snprintf_P(printBuffer_, sizeof(printBuffer_), PSTR("ERR: Unknown command '%s'"), cmd);
Serial.println(printBuffer_);
}
void SerialController::cmdEepromWrite(uint16_t addr, uint8_t value)
{
if (addr < 0 || addr >= EEPROM.length())
{
snprintf_P(printBuffer_, sizeof(printBuffer_), "ERR: Address %d out of range.", addr);
Serial.println(printBuffer_);
return;
}
if (value < 0 || value > 255)
{
Serial.println(F("ERR: Value must be 0..255."));
return;
}
EEPROM.write(addr, static_cast<uint8_t>(value));
snprintf_P(printBuffer_, sizeof(printBuffer_), PSTR("EW OK: [%d] = %d"), addr, value);
Serial.println(printBuffer_);
}
void SerialController::cmdEepromRead(uint16_t addr)
{
if (addr < 0 || addr >= EEPROM.length())
{
Serial.println(F("ERR: Address out of range."));
return;
}
uint8_t v = EEPROM.read(addr);
snprintf_P(printBuffer_, sizeof(printBuffer_), PSTR("ER: [%d] = %d"), addr, v);
Serial.println(printBuffer_);
} }
void SerialController::printHelp() void SerialController::printHelp()
{ {
Serial.println(F("=== Serial Control Help ===")); Serial.println(F("=== Serial Control Help ==="));
Serial.println(F("h - Show this help")); Serial.println(F("Basic commands (send + Enter):"));
Serial.println(F("d - Toggle debug output")); Serial.println(F(" HELP - Show this help"));
Serial.println(F("c - Request auto-calibration")); Serial.println(F(" DEBUG - Toggle debug output"));
Serial.println(F("s - Request save settings to EEPROM")); Serial.println(F(" CAL - Request auto-calibration"));
Serial.println(F("l - Request load settings from EEPROM")); Serial.println(F(" SAVE - Request save settings to EEPROM"));
Serial.println(F("r - Request load defaults")); Serial.println(F(" LOAD - Request load settings from EEPROM"));
Serial.println(F("x - Disable serial control, set target=0%")); Serial.println(F(" DEFAULTS - Request load defaults"));
Serial.println(F("+ - Increase target speed by 5%")); Serial.println(F(" X - Disable serial control, set target=0%"));
Serial.println(F("- - Decrease target speed by 5%")); Serial.println(F(" SPEED n - Set speed to n*10% (0..10)"));
Serial.println(F("0-9- Set target speed in 10% steps (0..100%)")); Serial.println(F(""));
Serial.println(F("EEPROM commands:"));
Serial.println(F(" EW <a> <v> - EEPROM write: address a, value v (0..255)"));
Serial.println(F(" ER <a> - EEPROM read: address a"));
} }

View File

@@ -2,8 +2,6 @@
#define SERIALCONTROLLER_H #define SERIALCONTROLLER_H
#include <Arduino.h> #include <Arduino.h>
#include "MotorController.h"
#include "PedalController.h"
typedef struct SerialSignals typedef struct SerialSignals
{ {
@@ -18,12 +16,12 @@ typedef struct SerialSignals
bool *serialControlEnabled; // schaltet „Serielle Steuerung“ an/aus bool *serialControlEnabled; // schaltet „Serielle Steuerung“ an/aus
} SerialSignals; } SerialSignals_t;
class SerialController class SerialController
{ {
public: public:
SerialController(const SerialSignals &signals); explicit SerialController(const SerialSignals_t &signals);
// im loop() aufrufen // im loop() aufrufen
void maintain(); void maintain();
@@ -32,9 +30,18 @@ public:
void printHelp(); void printHelp();
private: private:
SerialSignals signals_; SerialSignals_t signals_;
void handleCommand(char c); static const uint8_t CMD_BUFFER_SIZE = 32;
char cmdBuffer_[CMD_BUFFER_SIZE];
uint8_t cmdIndex_ = 0;
static const uint8_t PRINT_BUFFER_SIZE = 48;
char printBuffer_[PRINT_BUFFER_SIZE];
void handleCommand(char *line);
void cmdEepromWrite(uint16_t addr, uint8_t value);
void cmdEepromRead(uint16_t addr);
}; };
#endif #endif

38
src/Settings.cpp Normal file
View File

@@ -0,0 +1,38 @@
#include "Settings.h"
#include <EEPROM.h>
uint8_t calculateChecksum(const Settings_t &s)
{
uint8_t sum = 0;
const uint8_t *data = reinterpret_cast<const uint8_t *>(&s);
for (size_t i = 0; i < sizeof(Settings_t) - 1; i++)
{
sum ^= data[i];
}
return sum;
}
bool loadSettings(Settings_t &settings)
{
EEPROM.get(0, settings);
if (calculateChecksum(settings) != settings.checksum)
{
Serial.println(F("Invalid settings checksum, loading defaults."));
return false;
}
else
{
Serial.println(F("Settings loaded from EEPROM."));
return true;
}
}
void saveSettings(const Settings_t &settings)
{
Settings_t tmp = settings;
tmp.checksum = calculateChecksum(settings);
EEPROM.put(0, tmp);
Serial.println(F("Settings saved to EEPROM."));
}

22
src/Settings.h Normal file
View File

@@ -0,0 +1,22 @@
#pragma once
#include <Arduino.h>
#include "MotorController.h"
#include "PedalController.h"
typedef struct Settings
{
MotorConfig_t motorConfig;
PedalConfig_t pedalConfig;
uint8_t checksum;
}Settings_t;
bool loadSettings(Settings_t &settings);
void saveSettings(const Settings_t &settings);
uint8_t calculateChecksum(const Settings_t &s);
// optional:
inline size_t settingsSize()
{
return sizeof(Settings_t);
}

View File

@@ -1,6 +1,6 @@
#include <Arduino.h> #include <Arduino.h>
#include <EEPROM.h>
#include "Settings.h"
#include "MotorController.h" #include "MotorController.h"
#include "PedalController.h" #include "PedalController.h"
#include "SerialController.h" #include "SerialController.h"
@@ -35,9 +35,7 @@ bool gMotorEnabled = true;
// Globale Signale für Pedal // Globale Signale für Pedal
int16_t gPedalPercent = 0; int16_t gPedalPercent = 0;
int16_t gPedalRaw = 0;
bool gPedalCalibrated = false; bool gPedalCalibrated = false;
int16_t gPedalDigitalState = 0;
// Serial-Steuerflags // Serial-Steuerflags
bool gReqAutoCal = false; bool gReqAutoCal = false;
@@ -46,16 +44,8 @@ bool gReqLoadEEPROM = false;
bool gReqDefaults = false; bool gReqDefaults = false;
bool gSerialControl = false; bool gSerialControl = false;
// Combined settings structure
typedef struct Settings_t
{
MotorConfig motorConfig;
PedalConfig pedalConfig;
uint8_t checksum;
} Settings_s;
// Signals-Instanzen // Signals-Instanzen
MotorSignals motorSignals{ MotorSignals_t motorSignals{
.pwmPin = motorPwmPin, .pwmPin = motorPwmPin,
.targetSpeedPercent = &gTargetSpeedPercent, .targetSpeedPercent = &gTargetSpeedPercent,
.enabled = &gMotorEnabled, .enabled = &gMotorEnabled,
@@ -63,16 +53,14 @@ MotorSignals motorSignals{
.currentPWM = &gCurrentPwm, .currentPWM = &gCurrentPwm,
.debugFlag = &debug}; .debugFlag = &debug};
PedalSignals pedalSignals{ PedalSignals_t pedalSignals{
.analogPin = pedalPinAnalog, .analogPin = pedalPinAnalog,
.digitalPin = pedalPinDigital,
.debugFlag = &debug, .debugFlag = &debug,
.pedalPercent = &gPedalPercent, .pedalPercent = &gPedalPercent,
.rawValue = &gPedalRaw,
.calibrated = &gPedalCalibrated, .calibrated = &gPedalCalibrated,
.digitalState = &gPedalDigitalState}; };
SerialSignals serialSignals{ SerialSignals_t serialSignals{
.targetSpeedPercent = &gTargetSpeedPercent, .targetSpeedPercent = &gTargetSpeedPercent,
.debugFlag = &debug, .debugFlag = &debug,
.requestAutoCal = &gReqAutoCal, .requestAutoCal = &gReqAutoCal,
@@ -84,13 +72,10 @@ SerialSignals serialSignals{
// Global objects // Global objects
MotorController motor(motorSignals); MotorController motor(motorSignals);
PedalController pedal(pedalSignals, LOW); PedalController pedal(pedalSignals);
SerialController serialCtrl(serialSignals); SerialController serialCtrl(serialSignals);
// Function prototypes // Function prototypes
void loadSettings();
void saveSettings();
uint8_t calculateChecksum(const Settings_t &s);
void handleEncoder(); void handleEncoder();
void handleEncoderButton(); void handleEncoderButton();
void configurePWMFrequency(); void configurePWMFrequency();
@@ -119,7 +104,17 @@ void setup()
attachInterrupt(digitalPinToInterrupt(encoderButtonPin), handleEncoderButton, FALLING); attachInterrupt(digitalPinToInterrupt(encoderButtonPin), handleEncoderButton, FALLING);
Serial.begin(9600); Serial.begin(9600);
loadSettings();
Settings_t settings;
if (loadSettings(settings) == false)
{
motor.loadDefaults();
settings.motorConfig = motor.getConfig();
pedal.loadDefaults();
settings.pedalConfig = pedal.getConfig();
saveSettings(settings);
Serial.println(F("EEPROM Checksum mismatch, applied defaults"));
}
#ifdef DISPLAY_ENABLE #ifdef DISPLAY_ENABLE
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C))
@@ -153,14 +148,26 @@ void loop()
{ {
gReqLoadEEPROM = false; gReqLoadEEPROM = false;
Serial.println(F("Loading settings from EEPROM.")); Serial.println(F("Loading settings from EEPROM."));
loadSettings(); Settings_t settings;
if (loadSettings(settings) != false)
{
motor.setConfig(settings.motorConfig);
pedal.setConfig(settings.pedalConfig);
}
else
{
Serial.println(F("EEPROM Checksum mismatch, cannot Load"));
}
} }
if (gReqSaveEEPROM) if (gReqSaveEEPROM)
{ {
gReqSaveEEPROM = false; gReqSaveEEPROM = false;
Serial.println(F("Saving settings to EEPROM.")); Serial.println(F("Saving settings to EEPROM."));
saveSettings(); Settings_t settings{
.motorConfig = motor.getConfig(),
.pedalConfig = pedal.getConfig()};
saveSettings(settings);
} }
if (gReqAutoCal) if (gReqAutoCal)
@@ -197,7 +204,6 @@ void loop()
#ifdef DISPLAY_ENABLE #ifdef DISPLAY_ENABLE
updateDisplay(); updateDisplay();
#endif #endif
} }
// ----------------- HILFSFUNKTIONEN ----------------- // ----------------- HILFSFUNKTIONEN -----------------
@@ -207,54 +213,6 @@ void stopMotorAtNeedleUp()
motor.stopMotor(); motor.stopMotor();
} }
void loadSettings()
{
Settings_t tmp;
EEPROM.get(0, tmp);
if (calculateChecksum(tmp) != tmp.checksum)
{
Serial.println(F("Invalid settings checksum, loading defaults."));
motor.loadDefaults();
pedal.loadDefaults();
tmp.motorConfig = motor.getConfig();
tmp.pedalConfig = pedal.getConfig();
tmp.checksum = calculateChecksum(tmp);
EEPROM.put(0, tmp);
Serial.println(F("Defaults written to EEPROM."));
}
else
{
motor.setConfig(tmp.motorConfig);
pedal.setConfig(tmp.pedalConfig);
Serial.println(F("Settings loaded from EEPROM."));
}
}
void saveSettings()
{
Settings_t tmp;
tmp.motorConfig = motor.getConfig();
tmp.pedalConfig = pedal.getConfig();
tmp.checksum = calculateChecksum(tmp);
EEPROM.put(0, tmp);
Serial.println(F("Settings saved to EEPROM."));
}
uint8_t calculateChecksum(const Settings_t &s)
{
uint8_t sum = 0;
const uint8_t *data = reinterpret_cast<const uint8_t *>(&s);
for (size_t i = 0; i < sizeof(Settings_t) - 1; i++)
{
sum ^= data[i];
}
return sum;
}
void handleEncoder() void handleEncoder()
{ {
static uint8_t lastState = 0; static uint8_t lastState = 0;