reworked Settings-handling and tuned up CLI
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
#include "MotorController.h"
|
||||
|
||||
// Default-Konfiguration
|
||||
const MotorConfig defaultConfig = {
|
||||
const MotorConfig_t defaultConfig = {
|
||||
.minPWM = 0,
|
||||
.maxPWM = 255,
|
||||
.inverted = true,
|
||||
@@ -9,7 +9,7 @@ const MotorConfig defaultConfig = {
|
||||
.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)
|
||||
{
|
||||
loadDefaults();
|
||||
@@ -29,7 +29,7 @@ MotorController::MotorController(const MotorSignals &signals)
|
||||
lastSpeedPercent = 0;
|
||||
}
|
||||
|
||||
void MotorController::setSignals(const MotorSignals &signals)
|
||||
void MotorController::setSignals(const MotorSignals_t &signals)
|
||||
{
|
||||
signals_ = signals;
|
||||
|
||||
@@ -59,12 +59,12 @@ void MotorController::loadDefaults()
|
||||
}
|
||||
}
|
||||
|
||||
MotorConfig MotorController::getConfig() const
|
||||
MotorConfig_t MotorController::getConfig() const
|
||||
{
|
||||
return config;
|
||||
}
|
||||
|
||||
void MotorController::setConfig(const MotorConfig &newConfig)
|
||||
void MotorController::setConfig(const MotorConfig_t &newConfig)
|
||||
{
|
||||
config = newConfig;
|
||||
|
||||
@@ -105,7 +105,7 @@ void MotorController::maintain()
|
||||
lastSpeedPercent = adjustedSpeed;
|
||||
|
||||
// 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
|
||||
int16_t lowerIndex = (int16_t)pos;
|
||||
if (lowerIndex < 0)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
struct MotorConfig
|
||||
typedef struct MotorConfig
|
||||
{
|
||||
uint8_t minPWM;
|
||||
uint8_t maxPWM;
|
||||
@@ -11,7 +11,7 @@ struct MotorConfig
|
||||
int16_t responseSpeed; // Prozent pro Sekunde
|
||||
static const int16_t lookupTableSize = 10;
|
||||
uint8_t lookupTable[lookupTableSize];
|
||||
};
|
||||
}MotorConfig_t;
|
||||
|
||||
typedef struct MotorSignals
|
||||
{
|
||||
@@ -28,14 +28,14 @@ typedef struct MotorSignals
|
||||
|
||||
// Debug
|
||||
bool *debugFlag; // globales Debug-Flag
|
||||
} MotorSignals;
|
||||
} MotorSignals_t;
|
||||
|
||||
class MotorController
|
||||
{
|
||||
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
|
||||
void maintain();
|
||||
@@ -43,13 +43,13 @@ public:
|
||||
// Hard Stop
|
||||
void stopMotor();
|
||||
|
||||
MotorConfig getConfig() const;
|
||||
void setConfig(const MotorConfig &newConfig);
|
||||
MotorConfig_t getConfig() const;
|
||||
void setConfig(const MotorConfig_t &newConfig);
|
||||
void loadDefaults();
|
||||
|
||||
private:
|
||||
MotorSignals signals_;
|
||||
MotorConfig config;
|
||||
MotorSignals_t signals_;
|
||||
MotorConfig_t config;
|
||||
|
||||
// interner Dynamik-State
|
||||
int16_t smoothedPromille = 0; // 0..1000
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
// sinnvolle Defaults grob um den real genutzen Bereich
|
||||
// nicht gedrückt ~425, gedrückt ~227
|
||||
static const PedalConfig defaultConfig = {
|
||||
static const PedalConfig_t defaultConfig = {
|
||||
.minRaw = 230, // grob gedrückt
|
||||
.maxRaw = 420, // grob nicht gedrückt
|
||||
.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 DEFAULT_FS = 3; // Standard-Filterstärke
|
||||
|
||||
PedalController::PedalController(const PedalSignals &signals,
|
||||
uint8_t digitalNotPressedLevel_)
|
||||
PedalController::PedalController(const PedalSignals_t &signals)
|
||||
: signals_(signals),
|
||||
digitalNotPressedLevel(digitalNotPressedLevel_ ? 1 : 0),
|
||||
config(),
|
||||
filteredValue(-1),
|
||||
lastPedalPercent(0),
|
||||
@@ -46,12 +44,6 @@ PedalController::PedalController(const PedalSignals &signals,
|
||||
step3NearReleased(false),
|
||||
step4NearPressed(false)
|
||||
{
|
||||
// Digital-Pin als INPUT konfigurieren, falls vorhanden
|
||||
if (signals_.digitalPin >= 0)
|
||||
{
|
||||
pinMode(signals_.digitalPin, INPUT);
|
||||
}
|
||||
|
||||
loadDefaults();
|
||||
}
|
||||
|
||||
@@ -461,20 +453,6 @@ int16_t PedalController::getPedal()
|
||||
void PedalController::maintain()
|
||||
{
|
||||
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);
|
||||
lastPedalPercent = percent;
|
||||
|
||||
@@ -490,12 +468,12 @@ void PedalController::maintain()
|
||||
}
|
||||
}
|
||||
|
||||
PedalConfig PedalController::getConfig() const
|
||||
PedalConfig_t PedalController::getConfig() const
|
||||
{
|
||||
return config;
|
||||
}
|
||||
|
||||
void PedalController::setConfig(const PedalConfig &newConfig)
|
||||
void PedalController::setConfig(const PedalConfig_t &newConfig)
|
||||
{
|
||||
config = newConfig;
|
||||
|
||||
@@ -543,14 +521,9 @@ void PedalController::loadDefaults()
|
||||
step4NearPressed = false;
|
||||
}
|
||||
|
||||
void PedalController::setSignals(const PedalSignals &signals)
|
||||
void PedalController::setSignals(const PedalSignals_t &signals)
|
||||
{
|
||||
signals_ = signals;
|
||||
|
||||
if (signals_.digitalPin >= 0)
|
||||
{
|
||||
pinMode(signals_.digitalPin, INPUT);
|
||||
}
|
||||
}
|
||||
|
||||
void PedalController::printStatus(int16_t raw)
|
||||
@@ -571,17 +544,6 @@ void PedalController::printStatus(int16_t raw)
|
||||
Serial.print(raw);
|
||||
Serial.print(" Smooth=");
|
||||
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(firstReleased);
|
||||
Serial.print(" firstPress=");
|
||||
|
||||
@@ -12,37 +12,34 @@ enum CalibrationState
|
||||
ERROR
|
||||
};
|
||||
|
||||
struct PedalConfig
|
||||
typedef struct PedalConfig
|
||||
{
|
||||
int16_t minRaw;
|
||||
int16_t maxRaw;
|
||||
bool calibrated;
|
||||
uint8_t filterStrength;
|
||||
};
|
||||
}PedalConfig_t;
|
||||
|
||||
typedef struct PedalSignals
|
||||
{
|
||||
// Pins (by value)
|
||||
int16_t analogPin; // ADC-Pin
|
||||
int16_t digitalPin; // -1 falls unbenutzt
|
||||
|
||||
// Eingänge
|
||||
bool *debugFlag; // globales Debug-Flag
|
||||
|
||||
// Ausgänge
|
||||
int16_t *pedalPercent; // 0..100%
|
||||
int16_t *rawValue; // gefilterter Rawwert
|
||||
bool *calibrated; // Status
|
||||
int16_t *digitalState; // DO-Status oder -1
|
||||
} PedalSignals;
|
||||
|
||||
} PedalSignals_t;
|
||||
|
||||
class PedalController
|
||||
{
|
||||
public:
|
||||
PedalController(const PedalSignals &signals,
|
||||
uint8_t digitalNotPressedLevel = LOW);
|
||||
PedalController(const PedalSignals_t &signals);
|
||||
|
||||
void setSignals(const PedalSignals &signals);
|
||||
void setSignals(const PedalSignals_t &signals);
|
||||
|
||||
CalibrationState autoCalibrate(bool reset);
|
||||
CalibrationState getStatus() const;
|
||||
@@ -50,15 +47,14 @@ public:
|
||||
int16_t getPedal(); // alte API (blocking)
|
||||
void maintain(); // neue Non-Blocking-API
|
||||
|
||||
PedalConfig getConfig() const;
|
||||
void setConfig(const PedalConfig &cfg);
|
||||
PedalConfig_t getConfig() const;
|
||||
void setConfig(const PedalConfig_t &cfg);
|
||||
void loadDefaults();
|
||||
|
||||
private:
|
||||
PedalSignals signals_;
|
||||
uint8_t digitalNotPressedLevel; // nur Debug / Interpretation
|
||||
PedalSignals_t signals_;
|
||||
|
||||
PedalConfig config;
|
||||
PedalConfig_t config;
|
||||
int32_t filteredValue;
|
||||
int16_t lastPedalPercent;
|
||||
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
#include <Arduino.h>
|
||||
#include <EEPROM.h>
|
||||
#include "SerialController.h"
|
||||
|
||||
SerialController::SerialController(const SerialSignals &signals)
|
||||
SerialController::SerialController(const SerialSignals_t &signals)
|
||||
: signals_(signals)
|
||||
{
|
||||
cmdIndex_ = 0;
|
||||
}
|
||||
|
||||
void SerialController::maintain()
|
||||
@@ -11,145 +13,309 @@ void SerialController::maintain()
|
||||
while (Serial.available() > 0)
|
||||
{
|
||||
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)
|
||||
{
|
||||
case 'h':
|
||||
printHelp();
|
||||
break;
|
||||
// Leading Spaces entfernen
|
||||
while (*line == ' ' || *line == '\t')
|
||||
++line;
|
||||
|
||||
case 'd': // Debug toggeln
|
||||
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)
|
||||
{
|
||||
printHelp();
|
||||
return;
|
||||
}
|
||||
|
||||
// Debug toggle:
|
||||
if (strcmp(cmd, "DEBUG") == 0)
|
||||
{
|
||||
if (signals_.debugFlag)
|
||||
{
|
||||
*signals_.debugFlag = !*signals_.debugFlag;
|
||||
Serial.print("Debug: ");
|
||||
Serial.println(*signals_.debugFlag ? "ON" : "OFF");
|
||||
Serial.print(F("Debug: "));
|
||||
Serial.println(*signals_.debugFlag ? F("ON") : F("OFF"));
|
||||
}
|
||||
break;
|
||||
return;
|
||||
}
|
||||
|
||||
case '+': // Geschwindigkeit +5%
|
||||
if (signals_.targetSpeedPercent)
|
||||
// Serielles Save/Load/Defaults:
|
||||
if (strcmp(cmd, "SAVE") == 0)
|
||||
{
|
||||
if (signals_.requestSaveEEPROM)
|
||||
{
|
||||
if (signals_.serialControlEnabled)
|
||||
*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("%");
|
||||
*signals_.requestSaveEEPROM = true;
|
||||
Serial.println(F("Request: Save settings to EEPROM."));
|
||||
}
|
||||
break;
|
||||
return;
|
||||
}
|
||||
|
||||
case '-': // Geschwindigkeit -5%
|
||||
if (signals_.targetSpeedPercent)
|
||||
if (strcmp(cmd, "LOAD") == 0)
|
||||
{
|
||||
if (signals_.requestLoadEEPROM)
|
||||
{
|
||||
if (signals_.serialControlEnabled)
|
||||
*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("%");
|
||||
*signals_.requestLoadEEPROM = true;
|
||||
Serial.println(F("Request: Load settings from EEPROM."));
|
||||
}
|
||||
break;
|
||||
return;
|
||||
}
|
||||
|
||||
// direkte 0–100%-Vorgabe in 10%-Schritten
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
if (signals_.targetSpeedPercent)
|
||||
if (strcmp(cmd, "DEFAULTS") == 0)
|
||||
{
|
||||
if (signals_.requestLoadDefaults)
|
||||
{
|
||||
if (signals_.serialControlEnabled)
|
||||
*signals_.serialControlEnabled = true;
|
||||
|
||||
int16_t v = (c - '0') * 10;
|
||||
v = constrain(v, (int16_t)0, (int16_t)100);
|
||||
*signals_.targetSpeedPercent = v;
|
||||
|
||||
Serial.print("Target set: ");
|
||||
Serial.print(v);
|
||||
Serial.println("%");
|
||||
*signals_.requestLoadDefaults = true;
|
||||
Serial.println(F("Request: Load defaults."));
|
||||
}
|
||||
break;
|
||||
return;
|
||||
}
|
||||
|
||||
case 'x': // Serielle Steuerung stoppen & Motor freigeben
|
||||
// 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)
|
||||
*signals_.serialControlEnabled = false;
|
||||
if (signals_.targetSpeedPercent)
|
||||
*signals_.targetSpeedPercent = 0;
|
||||
|
||||
Serial.println("Serial control disabled, target=0%.");
|
||||
break;
|
||||
|
||||
case 'c': // Auto-Cal anfordern
|
||||
if (signals_.requestAutoCal)
|
||||
{
|
||||
*signals_.requestAutoCal = true;
|
||||
Serial.println("Request: Auto-Calibration.");
|
||||
}
|
||||
break;
|
||||
|
||||
case 's': // Save EEPROM
|
||||
if (signals_.requestSaveEEPROM)
|
||||
{
|
||||
*signals_.requestSaveEEPROM = true;
|
||||
Serial.println("Request: Save settings to EEPROM.");
|
||||
}
|
||||
break;
|
||||
|
||||
case 'l': // Load EEPROM
|
||||
if (signals_.requestLoadEEPROM)
|
||||
{
|
||||
*signals_.requestLoadEEPROM = true;
|
||||
Serial.println("Request: Load settings from EEPROM.");
|
||||
}
|
||||
break;
|
||||
|
||||
case 'r': // Defaults laden
|
||||
if (signals_.requestLoadDefaults)
|
||||
{
|
||||
*signals_.requestLoadDefaults = true;
|
||||
Serial.println("Request: Load defaults.");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// Optional: unerkanntes Kommando anzeigen
|
||||
// Serial.print("Unknown command: ");
|
||||
// Serial.println(c);
|
||||
break;
|
||||
Serial.println(F("Serial control disabled, target=0%."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(cmd, "SPEED") == 0)
|
||||
{
|
||||
if (!arg1)
|
||||
{
|
||||
Serial.println(F("ERR: SPEED requires: SPEED <0..10>"));
|
||||
return;
|
||||
}
|
||||
|
||||
int step = atoi(arg1); // 0..10
|
||||
int16_t v = (int16_t)(step * 10);
|
||||
v = constrain(v, (int16_t)0, (int16_t)100);
|
||||
|
||||
if (signals_.targetSpeedPercent)
|
||||
{
|
||||
if (signals_.serialControlEnabled)
|
||||
*signals_.serialControlEnabled = true;
|
||||
|
||||
*signals_.targetSpeedPercent = v;
|
||||
snprintf_P(printBuffer_, sizeof(printBuffer_), PSTR("Target speed set: %d%%"), v);
|
||||
Serial.println(printBuffer_);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// === EEPROM-Kommandos ===
|
||||
|
||||
if (strcmp(cmd, "EW") == 0)
|
||||
{
|
||||
// EW <addr> <value>
|
||||
if (!arg1 || !arg2)
|
||||
{
|
||||
Serial.println(F("ERR: EW requires: EW <addr> <value>"));
|
||||
return;
|
||||
}
|
||||
|
||||
int addr = atoi(arg1);
|
||||
int value = atoi(arg2);
|
||||
cmdEepromWrite(addr, value);
|
||||
return;
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
Serial.println(F("=== Serial Control Help ==="));
|
||||
Serial.println(F("h - Show this help"));
|
||||
Serial.println(F("d - Toggle debug output"));
|
||||
Serial.println(F("c - Request auto-calibration"));
|
||||
Serial.println(F("s - Request save settings to EEPROM"));
|
||||
Serial.println(F("l - Request load settings from EEPROM"));
|
||||
Serial.println(F("r - Request load defaults"));
|
||||
Serial.println(F("x - Disable serial control, set target=0%"));
|
||||
Serial.println(F("+ - Increase target speed by 5%"));
|
||||
Serial.println(F("- - Decrease target speed by 5%"));
|
||||
Serial.println(F("0-9- Set target speed in 10% steps (0..100%)"));
|
||||
Serial.println(F("Basic commands (send + Enter):"));
|
||||
Serial.println(F(" HELP - Show this help"));
|
||||
Serial.println(F(" DEBUG - Toggle debug output"));
|
||||
Serial.println(F(" CAL - Request auto-calibration"));
|
||||
Serial.println(F(" SAVE - Request save settings to EEPROM"));
|
||||
Serial.println(F(" LOAD - Request load settings from EEPROM"));
|
||||
Serial.println(F(" DEFAULTS - Request load defaults"));
|
||||
Serial.println(F(" X - Disable serial control, set target=0%"));
|
||||
Serial.println(F(" SPEED n - Set speed to n*10% (0..10)"));
|
||||
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"));
|
||||
}
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
#define SERIALCONTROLLER_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "MotorController.h"
|
||||
#include "PedalController.h"
|
||||
|
||||
typedef struct SerialSignals
|
||||
{
|
||||
@@ -18,12 +16,12 @@ typedef struct SerialSignals
|
||||
|
||||
bool *serialControlEnabled; // schaltet „Serielle Steuerung“ an/aus
|
||||
|
||||
} SerialSignals;
|
||||
} SerialSignals_t;
|
||||
|
||||
class SerialController
|
||||
{
|
||||
public:
|
||||
SerialController(const SerialSignals &signals);
|
||||
explicit SerialController(const SerialSignals_t &signals);
|
||||
|
||||
// im loop() aufrufen
|
||||
void maintain();
|
||||
@@ -32,9 +30,18 @@ public:
|
||||
void printHelp();
|
||||
|
||||
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
|
||||
|
||||
38
src/Settings.cpp
Normal file
38
src/Settings.cpp
Normal 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
22
src/Settings.h
Normal 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);
|
||||
}
|
||||
106
src/main.cpp
106
src/main.cpp
@@ -1,6 +1,6 @@
|
||||
#include <Arduino.h>
|
||||
#include <EEPROM.h>
|
||||
|
||||
#include "Settings.h"
|
||||
#include "MotorController.h"
|
||||
#include "PedalController.h"
|
||||
#include "SerialController.h"
|
||||
@@ -35,9 +35,7 @@ bool gMotorEnabled = true;
|
||||
|
||||
// Globale Signale für Pedal
|
||||
int16_t gPedalPercent = 0;
|
||||
int16_t gPedalRaw = 0;
|
||||
bool gPedalCalibrated = false;
|
||||
int16_t gPedalDigitalState = 0;
|
||||
|
||||
// Serial-Steuerflags
|
||||
bool gReqAutoCal = false;
|
||||
@@ -46,16 +44,8 @@ bool gReqLoadEEPROM = false;
|
||||
bool gReqDefaults = false;
|
||||
bool gSerialControl = false;
|
||||
|
||||
// Combined settings structure
|
||||
typedef struct Settings_t
|
||||
{
|
||||
MotorConfig motorConfig;
|
||||
PedalConfig pedalConfig;
|
||||
uint8_t checksum;
|
||||
} Settings_s;
|
||||
|
||||
// Signals-Instanzen
|
||||
MotorSignals motorSignals{
|
||||
MotorSignals_t motorSignals{
|
||||
.pwmPin = motorPwmPin,
|
||||
.targetSpeedPercent = &gTargetSpeedPercent,
|
||||
.enabled = &gMotorEnabled,
|
||||
@@ -63,16 +53,14 @@ MotorSignals motorSignals{
|
||||
.currentPWM = &gCurrentPwm,
|
||||
.debugFlag = &debug};
|
||||
|
||||
PedalSignals pedalSignals{
|
||||
PedalSignals_t pedalSignals{
|
||||
.analogPin = pedalPinAnalog,
|
||||
.digitalPin = pedalPinDigital,
|
||||
.debugFlag = &debug,
|
||||
.pedalPercent = &gPedalPercent,
|
||||
.rawValue = &gPedalRaw,
|
||||
.calibrated = &gPedalCalibrated,
|
||||
.digitalState = &gPedalDigitalState};
|
||||
};
|
||||
|
||||
SerialSignals serialSignals{
|
||||
SerialSignals_t serialSignals{
|
||||
.targetSpeedPercent = &gTargetSpeedPercent,
|
||||
.debugFlag = &debug,
|
||||
.requestAutoCal = &gReqAutoCal,
|
||||
@@ -84,13 +72,10 @@ SerialSignals serialSignals{
|
||||
|
||||
// Global objects
|
||||
MotorController motor(motorSignals);
|
||||
PedalController pedal(pedalSignals, LOW);
|
||||
PedalController pedal(pedalSignals);
|
||||
SerialController serialCtrl(serialSignals);
|
||||
|
||||
// Function prototypes
|
||||
void loadSettings();
|
||||
void saveSettings();
|
||||
uint8_t calculateChecksum(const Settings_t &s);
|
||||
void handleEncoder();
|
||||
void handleEncoderButton();
|
||||
void configurePWMFrequency();
|
||||
@@ -119,7 +104,17 @@ void setup()
|
||||
attachInterrupt(digitalPinToInterrupt(encoderButtonPin), handleEncoderButton, FALLING);
|
||||
|
||||
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
|
||||
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C))
|
||||
@@ -153,14 +148,26 @@ void loop()
|
||||
{
|
||||
gReqLoadEEPROM = false;
|
||||
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)
|
||||
{
|
||||
gReqSaveEEPROM = false;
|
||||
Serial.println(F("Saving settings to EEPROM."));
|
||||
saveSettings();
|
||||
Settings_t settings{
|
||||
.motorConfig = motor.getConfig(),
|
||||
.pedalConfig = pedal.getConfig()};
|
||||
saveSettings(settings);
|
||||
}
|
||||
|
||||
if (gReqAutoCal)
|
||||
@@ -197,7 +204,6 @@ void loop()
|
||||
#ifdef DISPLAY_ENABLE
|
||||
updateDisplay();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
// ----------------- HILFSFUNKTIONEN -----------------
|
||||
@@ -207,54 +213,6 @@ void stopMotorAtNeedleUp()
|
||||
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()
|
||||
{
|
||||
static uint8_t lastState = 0;
|
||||
@@ -308,4 +266,4 @@ void configurePWMFrequency()
|
||||
{
|
||||
// Configure Timer1 for higher PWM frequency (~4 kHz)
|
||||
TCCR1B = (1 << CS11); // Set prescaler to 8
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user