Compare commits
2 Commits
125fc17c39
...
c399672755
Author | SHA1 | Date | |
---|---|---|---|
c399672755 | |||
dd34bfe645 |
84
Software/Jenkinsfile
vendored
Normal file
84
Software/Jenkinsfile
vendored
Normal file
@ -0,0 +1,84 @@
|
||||
pipeline {
|
||||
agent any
|
||||
|
||||
options {
|
||||
timestamps()
|
||||
ansiColor('xterm')
|
||||
}
|
||||
|
||||
environment {
|
||||
// Default-Env, kann später via Parameter überschrieben werden
|
||||
BUILD_ENV = "pcb_rev_1-4_serial"
|
||||
PIO_HOME_DIR = "${WORKSPACE}/.pio"
|
||||
}
|
||||
|
||||
parameters {
|
||||
choice(
|
||||
name: 'BUILD_ENV',
|
||||
choices: ['pcb_rev_1-2_serial', 'pcb_rev_1-3_serial', 'pcb_rev_1-4_serial'],
|
||||
description: 'Welches Environment soll gebaut werden?'
|
||||
)
|
||||
}
|
||||
|
||||
stages {
|
||||
stage('🧼 Cleanup') {
|
||||
steps {
|
||||
deleteDir()
|
||||
}
|
||||
}
|
||||
|
||||
stage('Checkout') {
|
||||
steps {
|
||||
sshagent(['gitea-ssh']) {
|
||||
sh 'git clone git@git.hiabuto.net:souko/Kettenoeler.git .'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('🧪 Python & PlatformIO Setup') {
|
||||
steps {
|
||||
sh '''
|
||||
python3 -m venv .venv
|
||||
. .venv/bin/activate
|
||||
pip install --upgrade pip platformio
|
||||
'''
|
||||
}
|
||||
}
|
||||
|
||||
stage('📄 Dummy-Credential-Datei erstellen') {
|
||||
steps {
|
||||
writeFile file: 'wifi_credentials.ini', text: '''
|
||||
[wifi_cred]
|
||||
wifi_ssid_client = DummySSID
|
||||
wifi_password_client = DummyPass
|
||||
admin_password = Admin1234
|
||||
wifi_ap_password = ApPass1234
|
||||
'''.stripIndent()
|
||||
}
|
||||
}
|
||||
|
||||
stage('⚙️ Build Environment: ${params.BUILD_ENV}') {
|
||||
steps {
|
||||
sh '''
|
||||
. .venv/bin/activate
|
||||
platformio run -e ${BUILD_ENV}
|
||||
'''
|
||||
}
|
||||
}
|
||||
|
||||
stage('📦 Firmware sichern') {
|
||||
steps {
|
||||
archiveArtifacts artifacts: ".pio/build/${params.BUILD_ENV}/firmware.bin", fingerprint: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
success {
|
||||
echo "✅ Build erfolgreich abgeschlossen – Firmware liegt bereit als Artefakt."
|
||||
}
|
||||
failure {
|
||||
echo "💣 Build fehlgeschlagen – bitte Logs prüfen!"
|
||||
}
|
||||
}
|
||||
}
|
18
Software/include/button_actions.h
Normal file
18
Software/include/button_actions.h
Normal file
@ -0,0 +1,18 @@
|
||||
// === button_actions.h ===
|
||||
#ifndef _BUTTON_ACTIONS_H_
|
||||
#define _BUTTON_ACTIONS_H_
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "buttoncontrol.h"
|
||||
|
||||
// Deklarationen der Button-Callbacks
|
||||
void ButtonAction_ToggleMode();
|
||||
void ButtonAction_StartPurge();
|
||||
void ButtonAction_ToggleWiFi();
|
||||
void ButtonAction_WashMode();
|
||||
|
||||
// Bereitstellung der Aktionsliste
|
||||
extern const ButtonActionEntry buttonActions[];
|
||||
extern const uint8_t buttonActionCount;
|
||||
|
||||
#endif
|
30
Software/include/buttoncontrol.h
Normal file
30
Software/include/buttoncontrol.h
Normal file
@ -0,0 +1,30 @@
|
||||
// === buttoncontrol.h ===
|
||||
#ifndef _BUTTONCONTROL_H_
|
||||
#define _BUTTONCONTROL_H_
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
// Aktionen, die vom Button ausgelöst werden können
|
||||
enum ButtonAction
|
||||
{
|
||||
BTN_NONE,
|
||||
BTN_CUSTOM
|
||||
};
|
||||
|
||||
// Callback-Funktionstyp
|
||||
typedef void (*ButtonCallback)();
|
||||
|
||||
struct ButtonActionEntry
|
||||
{
|
||||
uint32_t holdTimeMs;
|
||||
uint32_t ledColor;
|
||||
ButtonCallback callback;
|
||||
};
|
||||
|
||||
// Initialisierung des Buttonmoduls
|
||||
void ButtonControl_Init(uint8_t pin, const ButtonActionEntry *actions, uint8_t actionCount);
|
||||
|
||||
// Muss regelmäßig in loop() aufgerufen werden
|
||||
void ButtonControl_Update();
|
||||
|
||||
#endif
|
@ -41,9 +41,10 @@
|
||||
#elif PCB_REV == 4
|
||||
#define GPIO_BUTTON D4
|
||||
#define GPIO_LED D3
|
||||
#define GPIO_TRIGGER D6
|
||||
#define GPIO_TRIGGER D8
|
||||
#define GPIO_PUMP D0
|
||||
#define GPIO_CS_CAN D8
|
||||
#define GPIO_CE_KLINE D8
|
||||
#endif
|
||||
|
||||
#ifndef HOST_NAME
|
||||
|
@ -16,19 +16,6 @@
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "webui.h"
|
||||
const char PROGMEM helpCmd[] = "sysinfo - System Info\n"
|
||||
"netinfo - WiFi Info\n"
|
||||
"formatPDS - Format Persistence EEPROM Data\n"
|
||||
"formatCFG - Format Configuration EEPROM Data\n"
|
||||
"checkEE - Check EEPROM with checksum\n"
|
||||
"dumpEE1k - dump the first 1kb of EEPROM to Serial\n"
|
||||
"dumpEE - dump the whole EPPROM to Serial\n"
|
||||
"resetPageEE - Reset the PersistenceData Page\n"
|
||||
"dumpCFG - print Config struct\n"
|
||||
"dumpPDS - print PersistanceStruct\n"
|
||||
"saveEE - save EE-Data\n"
|
||||
"showdtc - Show all DTCs\n"
|
||||
"dumpGlobals - print globals\n";
|
||||
|
||||
typedef enum DebugStatus_e
|
||||
{
|
||||
@ -49,6 +36,13 @@ const char sDebugPorts[dbg_cntElements][7] = {
|
||||
|
||||
extern DebugStatus_t DebuggerStatus[dbg_cntElements];
|
||||
|
||||
enum LogLevel
|
||||
{
|
||||
LOG_INFO,
|
||||
LOG_WARN,
|
||||
LOG_ERROR
|
||||
};
|
||||
|
||||
void initDebugger();
|
||||
void pushCANDebug(uint32_t id, uint8_t dlc, uint8_t *data);
|
||||
void Debug_pushMessage(const char *format, ...);
|
||||
|
33
Software/include/ledcontrol.h
Normal file
33
Software/include/ledcontrol.h
Normal file
@ -0,0 +1,33 @@
|
||||
// === ledcontrol.h ===
|
||||
#ifndef _LEDCONTROL_H_
|
||||
#define _LEDCONTROL_H_
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
// LED-Muster
|
||||
enum LedPattern
|
||||
{
|
||||
LED_PATTERN_ON,
|
||||
LED_PATTERN_FLASH,
|
||||
LED_PATTERN_FLASH_FAST,
|
||||
LED_PATTERN_BLINK,
|
||||
LED_PATTERN_BLINK_FAST,
|
||||
LED_PATTERN_BREATH
|
||||
};
|
||||
|
||||
// Initialisiert die LED-Steuerung
|
||||
void LEDControl_Init(uint8_t pin);
|
||||
|
||||
// Setzt den Basiszustand (Farbe + Pattern), wird verwendet wenn kein Override aktiv ist
|
||||
void LEDControl_SetBasic(uint32_t color, LedPattern pattern);
|
||||
|
||||
// Setzt ein Override mit Timeout (0 = bis explizit gecleart)
|
||||
void LEDControl_SetOverride(uint32_t color, LedPattern pattern, uint32_t durationMs);
|
||||
|
||||
// Hebt das Override wieder auf
|
||||
void LEDControl_ClearOverride();
|
||||
|
||||
// Muss regelmäßig aus loop() aufgerufen werden
|
||||
void LEDControl_Update();
|
||||
|
||||
#endif
|
@ -11,7 +11,7 @@
|
||||
[platformio]
|
||||
extra_configs =
|
||||
wifi_credentials.ini
|
||||
default_envs = pcb_rev_1-3_serial, pcb_rev_1-3_ota, pcb_rev_1-2_serial, pcb_rev_1-2_ota
|
||||
default_envs = pcb_rev_1-4_serial
|
||||
|
||||
[env]
|
||||
platform = espressif8266
|
||||
@ -51,6 +51,27 @@ lib_deps =
|
||||
coryjfowler/mcp_can @ ^1.5.0
|
||||
mikalhart/TinyGPSPlus @ ^1.0.3
|
||||
|
||||
[env:pcb_rev_1-4_serial]
|
||||
extends = env
|
||||
custom_pcb_revision = 4
|
||||
upload_protocol = esptool
|
||||
build_flags =
|
||||
${env.build_flags}
|
||||
-DPCB_REV=${this.custom_pcb_revision}
|
||||
board_build.ldscript = eagle.flash.4m1m.ld
|
||||
|
||||
[env:pcb_rev_1-4_ota]
|
||||
extends = env
|
||||
custom_pcb_revision = 4
|
||||
upload_protocol = espota
|
||||
upload_port = 10.0.1.14
|
||||
upload_flags =
|
||||
--port=8266
|
||||
--auth=${wifi_cred.admin_password}
|
||||
build_flags =
|
||||
${env.build_flags}
|
||||
-DPCB_REV=${this.custom_pcb_revision}
|
||||
board_build.ldscript = eagle.flash.4m1m.ld
|
||||
|
||||
[env:pcb_rev_1-3_serial]
|
||||
extends = env
|
||||
|
49
Software/src/button_actions.cpp
Normal file
49
Software/src/button_actions.cpp
Normal file
@ -0,0 +1,49 @@
|
||||
// === button_actions.cpp ===
|
||||
#include "button_actions.h"
|
||||
#include "globals.h"
|
||||
#include "debugger.h"
|
||||
#include "led_colors.h"
|
||||
|
||||
void ButtonAction_ToggleMode()
|
||||
{
|
||||
if (globals.systemStatus == sysStat_Normal)
|
||||
{
|
||||
globals.systemStatus = sysStat_Rain;
|
||||
globals.resumeStatus = sysStat_Rain;
|
||||
}
|
||||
else if (globals.systemStatus == sysStat_Rain)
|
||||
{
|
||||
globals.systemStatus = sysStat_Normal;
|
||||
globals.resumeStatus = sysStat_Normal;
|
||||
}
|
||||
Debug_pushMessage("Toggling Mode\n");
|
||||
}
|
||||
|
||||
void ButtonAction_StartPurge()
|
||||
{
|
||||
globals.systemStatus = sysStat_Purge;
|
||||
globals.purgePulses = LubeConfig.BleedingPulses;
|
||||
Debug_pushMessage("Starting Purge\n");
|
||||
}
|
||||
|
||||
void ButtonAction_ToggleWiFi()
|
||||
{
|
||||
extern void toggleWiFiAP(bool shutdown = false);
|
||||
toggleWiFiAP();
|
||||
Debug_pushMessage("Toggling WiFi\n");
|
||||
}
|
||||
|
||||
void ButtonAction_WashMode()
|
||||
{
|
||||
Debug_pushMessage("Wash mode not yet implemented\n");
|
||||
// TODO: Implementieren, sobald Verhalten klar ist
|
||||
}
|
||||
|
||||
// Liste der Aktionen, sortiert nach Mindest-Haltezeit (ms)
|
||||
const ButtonActionEntry buttonActions[] = {
|
||||
{500, LED_RAIN_COLOR, ButtonAction_ToggleMode},
|
||||
{3500, LED_PURGE_COLOR, ButtonAction_StartPurge},
|
||||
{6500, LED_WIFI_BLINK, ButtonAction_ToggleWiFi},
|
||||
{9500, COLOR_WARM_WHITE, ButtonAction_WashMode}};
|
||||
|
||||
const uint8_t buttonActionCount = sizeof(buttonActions) / sizeof(ButtonActionEntry);
|
64
Software/src/buttoncontrol.cpp
Normal file
64
Software/src/buttoncontrol.cpp
Normal file
@ -0,0 +1,64 @@
|
||||
|
||||
// === buttoncontrol.cpp ===
|
||||
#include "buttoncontrol.h"
|
||||
#include "ledcontrol.h" // Neue LED-Logik wird hier verwendet
|
||||
|
||||
static uint8_t btnPin;
|
||||
static uint32_t pressStart = 0;
|
||||
static bool pressed = false;
|
||||
static const ButtonActionEntry *btnActions = nullptr;
|
||||
static uint8_t btnActionCount = 0;
|
||||
static uint8_t currentActionIndex = 0xFF;
|
||||
static uint32_t lastColor = 0;
|
||||
|
||||
void ButtonControl_Init(uint8_t pin, const ButtonActionEntry *actions, uint8_t actionCount)
|
||||
{
|
||||
btnPin = pin;
|
||||
pinMode(btnPin, INPUT_PULLUP);
|
||||
btnActions = actions;
|
||||
btnActionCount = actionCount;
|
||||
}
|
||||
|
||||
void ButtonControl_Update()
|
||||
{
|
||||
bool currentState = digitalRead(btnPin) == LOW;
|
||||
uint32_t now = millis();
|
||||
|
||||
if (currentState && !pressed)
|
||||
{
|
||||
pressStart = now;
|
||||
pressed = true;
|
||||
currentActionIndex = 0xFF;
|
||||
lastColor = 0;
|
||||
}
|
||||
else if (currentState && pressed)
|
||||
{
|
||||
uint32_t duration = now - pressStart;
|
||||
// Finde passende Aktion basierend auf Zeit
|
||||
for (uint8_t i = 0; i < btnActionCount; i++)
|
||||
{
|
||||
if (duration >= btnActions[i].holdTimeMs)
|
||||
{
|
||||
if (currentActionIndex != i)
|
||||
{
|
||||
currentActionIndex = i;
|
||||
lastColor = btnActions[i].ledColor;
|
||||
// Farbe + Pattern setzen
|
||||
LEDControl_SetOverride(lastColor, LED_PATTERN_BREATH, 0); // Kein Timeout, wird bei Release beendet
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!currentState && pressed)
|
||||
{
|
||||
pressed = false;
|
||||
if (currentActionIndex != 0xFF && currentActionIndex < btnActionCount)
|
||||
{
|
||||
if (btnActions[currentActionIndex].callback)
|
||||
{
|
||||
btnActions[currentActionIndex].callback();
|
||||
}
|
||||
}
|
||||
LEDControl_ClearOverride(); // Override-Modus zurücksetzen
|
||||
}
|
||||
}
|
@ -12,6 +12,9 @@
|
||||
*/
|
||||
|
||||
#include "debugger.h"
|
||||
#include <map>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
DebugStatus_t DebuggerStatus[dbg_cntElements];
|
||||
|
||||
@ -94,10 +97,9 @@ void Debug_Process()
|
||||
}
|
||||
|
||||
// Check for input buffer overflow
|
||||
if (inputCnt > sizeof(inputBuffer))
|
||||
{
|
||||
if (inputCnt >= sizeof(inputBuffer) - 1) {
|
||||
inputBuffer[sizeof(inputBuffer) - 1] = '\0';
|
||||
inputCnt = 0;
|
||||
inputBuffer[sizeof(inputBuffer) - 1] = 0; // terminate the String
|
||||
InputProcessed = CMD_OVERFLOW;
|
||||
}
|
||||
}
|
||||
@ -147,6 +149,29 @@ void SetDebugportStatus(DebugPorts_t port, DebugStatus_t status)
|
||||
Debug_pushMessage("Enabled DebugPort %s\n", sDebugPorts[port]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Debug_log(LogLevel level, const char *format, ...)
|
||||
{
|
||||
if ((DebuggerStatus[dbg_Serial] == enabled) || (DebuggerStatus[dbg_Webui] == enabled))
|
||||
{
|
||||
char buff[128];
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
vsnprintf(buff, sizeof(buff), format, arg);
|
||||
va_end(arg);
|
||||
|
||||
if (DebuggerStatus[dbg_Serial] == enabled)
|
||||
{
|
||||
Serial.print(buff);
|
||||
}
|
||||
if (DebuggerStatus[dbg_Webui] == enabled)
|
||||
{
|
||||
Websocket_PushLiveDebug(String(buff));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Pushes a formatted debug message to the enabled debug ports (Serial or WebUI).
|
||||
*
|
||||
@ -218,68 +243,99 @@ void pushCANDebug(uint32_t id, uint8_t dlc, uint8_t *data)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Processes a debug command and performs corresponding actions.
|
||||
*
|
||||
* @param command The debug command to be processed.
|
||||
*/
|
||||
void processCmdDebug(String command)
|
||||
// === splitArgs Helper ===
|
||||
std::vector<String> splitArgs(const String &input)
|
||||
{
|
||||
// Check the received command and execute corresponding actions
|
||||
if (command == "help")
|
||||
Debug_printHelp();
|
||||
else if (command == "sysinfo")
|
||||
Debug_printSystemInfo();
|
||||
else if (command == "netinfo")
|
||||
Debug_printWifiInfo();
|
||||
else if (command == "formatCFG")
|
||||
Debug_formatCFG();
|
||||
else if (command == "formatPDS")
|
||||
Debug_formatPersistence();
|
||||
else if (command == "checkEE")
|
||||
Debug_CheckEEPOM(false);
|
||||
else if (command == "checkEEfix")
|
||||
Debug_CheckEEPOM(true);
|
||||
else if (command == "dumpEE1k")
|
||||
dumpEEPROM(0, 1024);
|
||||
else if (command == "dumpEE")
|
||||
dumpEEPROM(0, EEPROM_SIZE_BYTES);
|
||||
else if (command == "resetPageEE")
|
||||
MovePersistencePage_EEPROM(true);
|
||||
else if (command == "dumpCFG")
|
||||
Debug_dumpConfig();
|
||||
else if (command == "dumpPDS")
|
||||
Debug_dumpPersistance();
|
||||
else if (command == "saveEE")
|
||||
globals.requestEEAction = EE_ALL_SAVE;
|
||||
else if (command == "dumpGlobals")
|
||||
Debug_dumpGlobals();
|
||||
else if (command == "sdbg")
|
||||
SetDebugportStatus(dbg_Serial, enabled);
|
||||
else if (command == "dtc_show")
|
||||
Debug_ShowDTCs();
|
||||
else if (command == "dtc_clear")
|
||||
ClearAllDTC();
|
||||
else if (command == "dtc_crit")
|
||||
MaintainDTC(DTC_FAKE_DTC_CRIT, true, millis());
|
||||
else if (command == "dtc_warn")
|
||||
MaintainDTC(DTC_FAKE_DTC_WARN, true, millis());
|
||||
else if (command == "dtc_info")
|
||||
MaintainDTC(DTC_FAKE_DTC_INFO, true, millis());
|
||||
else if (command == "notify_error")
|
||||
Websocket_PushNotification("Debug Error Notification", error);
|
||||
else if (command == "notify_warning")
|
||||
Websocket_PushNotification("Debug Warning Notification", warning);
|
||||
else if (command == "notify_success")
|
||||
Websocket_PushNotification("Debug Success Notification", success);
|
||||
else if (command == "notify_info")
|
||||
Websocket_PushNotification("Debug Info Notification", info);
|
||||
else if (command == "purge")
|
||||
Debug_Purge();
|
||||
else if (command == "toggle_wifi")
|
||||
globals.toggle_wifi = true;
|
||||
std::vector<String> tokens;
|
||||
int start = 0, end = 0;
|
||||
while ((end = input.indexOf(' ', start)) != -1)
|
||||
{
|
||||
tokens.push_back(input.substring(start, end));
|
||||
start = end + 1;
|
||||
}
|
||||
if (start < input.length())
|
||||
tokens.push_back(input.substring(start));
|
||||
return tokens;
|
||||
}
|
||||
|
||||
// === getArg helper ===
|
||||
String getArg(const std::vector<String> &args, size_t index, const String &defaultVal = "")
|
||||
{
|
||||
if (index < args.size())
|
||||
return args[index];
|
||||
return defaultVal;
|
||||
}
|
||||
|
||||
// === Command Handler Map ===
|
||||
typedef std::function<void(const String &args)> DebugCmdHandler;
|
||||
|
||||
static const std::map<String, DebugCmdHandler> &getCmdMap()
|
||||
{
|
||||
static const std::map<String, DebugCmdHandler> cmdMap = {
|
||||
{"help", [](const String &) {
|
||||
Debug_log(LOG_INFO, "Available commands:\n");
|
||||
for (const auto &entry : getCmdMap())
|
||||
Debug_log(LOG_INFO, " - %s\n", entry.first.c_str());
|
||||
}},
|
||||
{"sysinfo", [](const String &) { Debug_printSystemInfo(); }},
|
||||
{"netinfo", [](const String &) { Debug_printWifiInfo(); }},
|
||||
{"formatCFG", [](const String &) { Debug_formatCFG(); }},
|
||||
{"formatPDS", [](const String &) { Debug_formatPersistence(); }},
|
||||
{"checkEE", [](const String &) { Debug_CheckEEPOM(false); }},
|
||||
{"checkEEfix", [](const String &) { Debug_CheckEEPOM(true); }},
|
||||
{"dumpEE1k", [](const String &) { dumpEEPROM(0, 1024); }},
|
||||
{"dumpEE", [](const String &args) {
|
||||
int start = 0, len = EEPROM_SIZE_BYTES;
|
||||
auto tokens = splitArgs(args);
|
||||
if (tokens.size() >= 2)
|
||||
{
|
||||
start = tokens[0].toInt();
|
||||
len = tokens[1].toInt();
|
||||
}
|
||||
dumpEEPROM(start, len);
|
||||
}},
|
||||
{"resetPageEE", [](const String &) { MovePersistencePage_EEPROM(true); }},
|
||||
{"dumpCFG", [](const String &) { Debug_dumpConfig(); }},
|
||||
{"dumpPDS", [](const String &) { Debug_dumpPersistance(); }},
|
||||
{"saveEE", [](const String &) { globals.requestEEAction = EE_ALL_SAVE; }},
|
||||
{"dumpGlobals", [](const String &) { Debug_dumpGlobals(); }},
|
||||
{"sdbg", [](const String &) { SetDebugportStatus(dbg_Serial, enabled); }},
|
||||
{"dtc_show", [](const String &) { Debug_ShowDTCs(); }},
|
||||
{"dtc_clear", [](const String &) { ClearAllDTC(); }},
|
||||
{"dtc_crit", [](const String &) { MaintainDTC(DTC_FAKE_DTC_CRIT, true, millis()); }},
|
||||
{"dtc_warn", [](const String &) { MaintainDTC(DTC_FAKE_DTC_WARN, true, millis()); }},
|
||||
{"dtc_info", [](const String &) { MaintainDTC(DTC_FAKE_DTC_INFO, true, millis()); }},
|
||||
{"notify_error", [](const String &) { Websocket_PushNotification("Debug Error Notification", error); }},
|
||||
{"notify_warning", [](const String &) { Websocket_PushNotification("Debug Warning Notification", warning); }},
|
||||
{"notify_success", [](const String &) { Websocket_PushNotification("Debug Success Notification", success); }},
|
||||
{"notify_info", [](const String &) { Websocket_PushNotification("Debug Info Notification", info); }},
|
||||
{"purge", [](const String &) { Debug_Purge(); }},
|
||||
{"toggle_wifi", [](const String &) { globals.toggle_wifi = true; }},
|
||||
{"dtc_add", [](const String &args) {
|
||||
auto tokens = splitArgs(args);
|
||||
if (!tokens.empty())
|
||||
{
|
||||
int code = tokens[0].toInt();
|
||||
MaintainDTC((DTCNum_t)code, true, millis());
|
||||
}
|
||||
}}
|
||||
};
|
||||
return cmdMap;
|
||||
}
|
||||
|
||||
void processCmdDebug(String input)
|
||||
{
|
||||
input.trim();
|
||||
int splitIndex = input.indexOf(' ');
|
||||
String command = splitIndex == -1 ? input : input.substring(0, splitIndex);
|
||||
String args = splitIndex == -1 ? "" : input.substring(splitIndex + 1);
|
||||
|
||||
auto &cmdMap = getCmdMap();
|
||||
auto it = cmdMap.find(command);
|
||||
if (it != cmdMap.end())
|
||||
it->second(args);
|
||||
else
|
||||
Debug_pushMessage("unknown Command\n");
|
||||
Debug_log(LOG_WARN, "Unknown command: '%s'\n", command.c_str());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -473,25 +529,6 @@ void Debug_ShowDTCs()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Displays the help commands for debugging through Serial or WebUI.
|
||||
* Each command is printed individually in a formatted manner.
|
||||
*/
|
||||
void Debug_printHelp()
|
||||
{
|
||||
char buff[64];
|
||||
|
||||
// Iterate through helpCmd and display each command
|
||||
for (unsigned int i = 0; i < sizeof(helpCmd) / 63; i++)
|
||||
{
|
||||
// Copy a portion of helpCmd to buff for display
|
||||
memcpy_P(buff, (helpCmd + (i * 63)), 63);
|
||||
buff[63] = 0;
|
||||
|
||||
// Display the help command
|
||||
Debug_pushMessage(buff);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start purging for 10 pulses.
|
||||
|
106
Software/src/ledcontrol.cpp
Normal file
106
Software/src/ledcontrol.cpp
Normal file
@ -0,0 +1,106 @@
|
||||
|
||||
// === ledcontrol.cpp ===
|
||||
#include "ledcontrol.h"
|
||||
#include <Adafruit_NeoPixel.h>
|
||||
#include "globals.h"
|
||||
|
||||
static Adafruit_NeoPixel leds(1, GPIO_LED, NEO_RGB + NEO_KHZ800);
|
||||
|
||||
static uint32_t basicColor = 0x000000;
|
||||
static LedPattern basicPattern = LED_PATTERN_ON;
|
||||
|
||||
static uint32_t overrideColor = 0;
|
||||
static LedPattern overridePattern = LED_PATTERN_ON;
|
||||
static uint32_t overrideEndTime = 0;
|
||||
static bool overrideActive = false;
|
||||
|
||||
void LEDControl_Init(uint8_t pin)
|
||||
{
|
||||
leds.begin();
|
||||
leds.setBrightness(LubeConfig.LED_Max_Brightness);
|
||||
leds.setPixelColor(0, 0);
|
||||
leds.show();
|
||||
}
|
||||
|
||||
void LEDControl_SetBasic(uint32_t color, LedPattern pattern)
|
||||
{
|
||||
basicColor = color;
|
||||
basicPattern = pattern;
|
||||
}
|
||||
|
||||
void LEDControl_SetOverride(uint32_t color, LedPattern pattern, uint32_t durationMs)
|
||||
{
|
||||
overrideColor = color;
|
||||
overridePattern = pattern;
|
||||
overrideEndTime = millis() + durationMs;
|
||||
overrideActive = true;
|
||||
if (durationMs == 0)
|
||||
overrideEndTime = 0xFFFFFFFF; // Kein Timeout
|
||||
}
|
||||
|
||||
void LEDControl_ClearOverride()
|
||||
{
|
||||
overrideActive = false;
|
||||
overrideEndTime = 0;
|
||||
}
|
||||
|
||||
void LEDControl_Update()
|
||||
{
|
||||
uint32_t now = millis();
|
||||
uint32_t color = basicColor;
|
||||
LedPattern pattern = basicPattern;
|
||||
|
||||
// Check override
|
||||
if (overrideActive)
|
||||
{
|
||||
if (overrideEndTime != 0xFFFFFFFF && now >= overrideEndTime)
|
||||
{
|
||||
LEDControl_ClearOverride();
|
||||
}
|
||||
else
|
||||
{
|
||||
color = overrideColor;
|
||||
pattern = overridePattern;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t brightness = LubeConfig.LED_Min_Brightness;
|
||||
bool on = true;
|
||||
|
||||
switch (pattern)
|
||||
{
|
||||
case LED_PATTERN_ON:
|
||||
brightness = LubeConfig.LED_Max_Brightness;
|
||||
break;
|
||||
|
||||
case LED_PATTERN_FLASH:
|
||||
on = (now % 1000) < 100;
|
||||
brightness = LubeConfig.LED_Max_Brightness;
|
||||
break;
|
||||
|
||||
case LED_PATTERN_FLASH_FAST:
|
||||
on = (now % 500) < 50;
|
||||
brightness = LubeConfig.LED_Max_Brightness;
|
||||
break;
|
||||
|
||||
case LED_PATTERN_BLINK:
|
||||
on = (now % 1000) < 500;
|
||||
brightness = on ? LubeConfig.LED_Max_Brightness : 0;
|
||||
break;
|
||||
|
||||
case LED_PATTERN_BLINK_FAST:
|
||||
on = (now % 400) < 200;
|
||||
brightness = on ? LubeConfig.LED_Max_Brightness : 0;
|
||||
break;
|
||||
|
||||
case LED_PATTERN_BREATH:
|
||||
brightness = map(now % 2000, 0, 1000, LubeConfig.LED_Min_Brightness, LubeConfig.LED_Max_Brightness);
|
||||
if ((now % 2000) >= 1000)
|
||||
brightness = LubeConfig.LED_Max_Brightness - (brightness - LubeConfig.LED_Min_Brightness);
|
||||
break;
|
||||
}
|
||||
|
||||
leds.setBrightness(brightness);
|
||||
leds.setPixelColor(0, on ? color : 0);
|
||||
leds.show();
|
||||
}
|
@ -39,6 +39,10 @@
|
||||
#include "led_colors.h"
|
||||
#include "obd2_kline.h"
|
||||
#include "obd2_can.h"
|
||||
#include "buttoncontrol.h"
|
||||
#include "button_actions.h"
|
||||
#include "ledcontrol.h"
|
||||
|
||||
|
||||
#ifdef FEATURE_ENABLE_WIFI_CLIENT
|
||||
#include <ESP8266WiFiMulti.h>
|
||||
@ -59,12 +63,10 @@ Adafruit_NeoPixel leds(1, GPIO_LED, NEO_RGB + NEO_KHZ800);
|
||||
|
||||
// Function-Prototypes
|
||||
void IRAM_ATTR trigger_ISR();
|
||||
void LED_Process(uint8_t override = false, uint32_t setColor = LED_DEFAULT_COLOR);
|
||||
#ifdef FEATURE_ENABLE_OLED
|
||||
U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(-1);
|
||||
void Display_Process();
|
||||
#endif
|
||||
void Button_Process();
|
||||
void toggleWiFiAP(bool shutdown = false);
|
||||
void SystemShutdown(bool restart = false);
|
||||
uint32_t Process_Impulse_WheelSpeed();
|
||||
@ -134,7 +136,7 @@ void setup()
|
||||
Serial.print("\nEE-Init done");
|
||||
|
||||
// Initialize LEDs
|
||||
leds.begin();
|
||||
LEDControl_Init(GPIO_LED);
|
||||
Serial.print("\nLED-Init done");
|
||||
|
||||
// Initialize based on the chosen speed source (CAN, GPS, Impulse)
|
||||
@ -175,6 +177,8 @@ void setup()
|
||||
pinMode(GPIO_BUTTON, INPUT_PULLUP);
|
||||
pinMode(GPIO_PUMP, OUTPUT);
|
||||
|
||||
ButtonControl_Init(GPIO_BUTTON, buttonActions, buttonActionCount);
|
||||
|
||||
// Set up OTA updates
|
||||
ArduinoOTA.setPort(8266);
|
||||
ArduinoOTA.setHostname(globals.DeviceName);
|
||||
@ -249,8 +253,8 @@ void loop()
|
||||
|
||||
// Process button input, manage LED behavior, perform EEPROM tasks, handle webserver operations,
|
||||
// process Diagnostic Trouble Codes (DTC), and manage debugging
|
||||
Button_Process();
|
||||
LED_Process();
|
||||
ButtonControl_Update();
|
||||
LEDControl_Update();
|
||||
EEPROM_Process();
|
||||
Webserver_Process();
|
||||
DTC_Process();
|
||||
@ -340,208 +344,6 @@ void trigger_ISR()
|
||||
wheel_pulse++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Manages LED behavior based on the current system status and user overrides.
|
||||
*
|
||||
* This function handles LED behavior, including startup animations, confirmation animations for
|
||||
* normal and rain modes, indication for purge, error, shutdown, and normal operation. It supports
|
||||
* user overrides to set a specific LED color. The LED status is determined by the current system
|
||||
* status, and specific LED patterns are displayed accordingly.
|
||||
*
|
||||
* @param override Flag indicating whether to override the LED behavior (0: No override, 1: Override, 2: Resume previous state).
|
||||
* @param SetColor The color to set when overriding the LED behavior.
|
||||
*/
|
||||
void LED_Process(uint8_t override, uint32_t SetColor)
|
||||
{
|
||||
// Enumeration to represent LED status
|
||||
typedef enum
|
||||
{
|
||||
LED_Startup,
|
||||
LED_Normal,
|
||||
LED_Confirm_Normal,
|
||||
LED_Rain,
|
||||
LED_Confirm_Rain,
|
||||
LED_Purge,
|
||||
LED_Error,
|
||||
LED_Shutdown,
|
||||
LED_Override
|
||||
} tLED_Status;
|
||||
|
||||
// Static variables to track LED status, system status, override color, and previous LED status
|
||||
static tSystem_Status oldSysStatus = sysStat_Startup;
|
||||
static tLED_Status LED_Status = LED_Startup;
|
||||
static uint32_t LED_override_color = 0;
|
||||
static tLED_Status LED_ResumeOverrideStatus = LED_Startup;
|
||||
|
||||
// Variables for managing LED animation timing
|
||||
uint8_t color = 0;
|
||||
uint32_t timer = 0;
|
||||
uint32_t animtimer = 0;
|
||||
static uint32_t timestamp = 0;
|
||||
timer = millis();
|
||||
|
||||
// Handle LED overrides
|
||||
if (override == 1)
|
||||
{
|
||||
if (LED_Status != LED_Override)
|
||||
{
|
||||
LED_ResumeOverrideStatus = LED_Status;
|
||||
Debug_pushMessage("Override LED_Status\n");
|
||||
}
|
||||
LED_Status = LED_Override;
|
||||
LED_override_color = SetColor;
|
||||
}
|
||||
|
||||
if (override == 2)
|
||||
{
|
||||
if (LED_Status == LED_Override)
|
||||
{
|
||||
LED_Status = LED_ResumeOverrideStatus;
|
||||
Debug_pushMessage("Resume LED_Status\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Update LED status when system status changes
|
||||
if (oldSysStatus != globals.systemStatus)
|
||||
{
|
||||
switch (globals.systemStatus)
|
||||
{
|
||||
case sysStat_Startup:
|
||||
LED_Status = LED_Startup;
|
||||
Debug_pushMessage("sysStat: Startup\n");
|
||||
break;
|
||||
case sysStat_Normal:
|
||||
timestamp = timer + 3500;
|
||||
LED_Status = LED_Confirm_Normal;
|
||||
Debug_pushMessage("sysStat: Normal\n");
|
||||
break;
|
||||
case sysStat_Rain:
|
||||
timestamp = timer + 3500;
|
||||
LED_Status = LED_Confirm_Rain;
|
||||
Debug_pushMessage("sysStat: Rain\n");
|
||||
break;
|
||||
case sysStat_Purge:
|
||||
LED_Status = LED_Purge;
|
||||
Debug_pushMessage("sysStat: Purge\n");
|
||||
break;
|
||||
case sysStat_Error:
|
||||
LED_Status = LED_Error;
|
||||
Debug_pushMessage("sysStat: Error\n");
|
||||
break;
|
||||
case sysStat_Shutdown:
|
||||
LED_Status = LED_Shutdown;
|
||||
Debug_pushMessage("sysStat: Shutdown\n");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
oldSysStatus = globals.systemStatus;
|
||||
}
|
||||
|
||||
// Handle different LED statuses
|
||||
switch (LED_Status)
|
||||
{
|
||||
case LED_Startup:
|
||||
leds.setBrightness(LubeConfig.LED_Max_Brightness);
|
||||
|
||||
if (globals.TankPercentage < LubeConfig.TankRemindAtPercentage)
|
||||
leds.setPixelColor(0, LED_STARTUP_TANKWARN);
|
||||
else
|
||||
leds.setPixelColor(0, LED_STARTUP_NORMAL);
|
||||
break;
|
||||
|
||||
case LED_Confirm_Normal:
|
||||
animtimer = timer % 500;
|
||||
color = map(animtimer / 2, 0, 250, 0, LubeConfig.LED_Max_Brightness);
|
||||
leds.setPixelColor(0, LED_NORMAL_COLOR);
|
||||
if (animtimer < 250)
|
||||
leds.setBrightness(color);
|
||||
else
|
||||
leds.setBrightness(LubeConfig.LED_Max_Brightness - color);
|
||||
|
||||
if (timestamp < timer)
|
||||
{
|
||||
LED_Status = LED_Normal;
|
||||
Debug_pushMessage("LED_Status: Confirm -> Normal\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case LED_Normal:
|
||||
leds.setBrightness(LubeConfig.LED_Min_Brightness);
|
||||
leds.setPixelColor(0, LED_NORMAL_COLOR);
|
||||
|
||||
if (timer % 2000 > 1950 && LubeConfig.LED_Mode_Flash == true)
|
||||
leds.setBrightness(LubeConfig.LED_Max_Brightness);
|
||||
else if (timer % 2000 > 1500 && WiFi.getMode() != WIFI_OFF)
|
||||
leds.setPixelColor(0, LED_WIFI_BLINK);
|
||||
|
||||
break;
|
||||
|
||||
case LED_Confirm_Rain:
|
||||
animtimer = timer % 500;
|
||||
color = map(animtimer / 2, 0, 250, 0, LubeConfig.LED_Max_Brightness);
|
||||
leds.setPixelColor(0, LED_RAIN_COLOR);
|
||||
if (animtimer < 250)
|
||||
leds.setBrightness(color);
|
||||
else
|
||||
leds.setBrightness(LubeConfig.LED_Max_Brightness - color);
|
||||
if (timestamp < timer)
|
||||
{
|
||||
LED_Status = LED_Rain;
|
||||
Debug_pushMessage("LED_Status: Confirm -> Rain\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case LED_Rain:
|
||||
leds.setBrightness(LubeConfig.LED_Min_Brightness);
|
||||
leds.setPixelColor(0, LED_RAIN_COLOR);
|
||||
|
||||
if (timer % 2000 > 1950 && LubeConfig.LED_Mode_Flash == true)
|
||||
leds.setBrightness(LubeConfig.LED_Max_Brightness);
|
||||
else if (timer % 2000 > 1500 && WiFi.getMode() != WIFI_OFF)
|
||||
leds.setPixelColor(0, LED_WIFI_BLINK);
|
||||
|
||||
break;
|
||||
|
||||
case LED_Purge:
|
||||
timer = timer % 500;
|
||||
color = map(timer / 2, 0, 250, LubeConfig.LED_Min_Brightness, LubeConfig.LED_Max_Brightness);
|
||||
leds.setPixelColor(0, LED_PURGE_COLOR);
|
||||
if (timer < 250)
|
||||
leds.setBrightness(color);
|
||||
else
|
||||
leds.setBrightness(LubeConfig.LED_Max_Brightness - color);
|
||||
break;
|
||||
|
||||
case LED_Error:
|
||||
leds.setBrightness(LubeConfig.LED_Max_Brightness);
|
||||
leds.setPixelColor(0, timer % 500 > 250 ? LED_ERROR_BLINK : 0);
|
||||
break;
|
||||
|
||||
case LED_Shutdown:
|
||||
timer = timer % 600;
|
||||
leds.setPixelColor(0, LED_SHUTDOWN_BLINK);
|
||||
if (timer < 500)
|
||||
{
|
||||
color = map(timer, 0, 500, LubeConfig.LED_Max_Brightness, LubeConfig.LED_Min_Brightness);
|
||||
leds.setBrightness(color);
|
||||
}
|
||||
else
|
||||
{
|
||||
leds.setBrightness(LubeConfig.LED_Min_Brightness);
|
||||
}
|
||||
break;
|
||||
|
||||
case LED_Override:
|
||||
leds.setBrightness(LubeConfig.LED_Max_Brightness);
|
||||
leds.setPixelColor(0, LED_override_color);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
leds.show();
|
||||
}
|
||||
|
||||
#ifdef FEATURE_ENABLE_OLED
|
||||
/**
|
||||
@ -597,119 +399,6 @@ void Display_Process()
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Processes the button input and performs corresponding actions based on button state and timing.
|
||||
*
|
||||
* This function handles the button input, detecting button presses and executing actions based on
|
||||
* predefined time delays. Actions include toggling WiFi, starting purge, toggling operating modes,
|
||||
* and displaying feedback through LEDs. The function utilizes an enumeration to track button actions
|
||||
* and manages the timing for different actions.
|
||||
*/
|
||||
void Button_Process()
|
||||
{
|
||||
// Time delays for different button actions
|
||||
#define BUTTON_ACTION_DELAY_TOGGLEMODE 500
|
||||
#define BUTTON_ACTION_DELAY_PURGE 3500
|
||||
#define BUTTON_ACTION_DELAY_WIFI 6500
|
||||
#define BUTTON_ACTION_DELAY_NOTHING 9500
|
||||
|
||||
// Enumeration to represent button actions
|
||||
typedef enum buttonAction_e
|
||||
{
|
||||
BTN_INACTIVE,
|
||||
BTN_NOTHING,
|
||||
BTN_TOGGLEMODE,
|
||||
BTN_TOGGLEWIFI,
|
||||
BTN_STARTPURGE
|
||||
} buttonAction_t;
|
||||
|
||||
// Static variables to track button state and timing
|
||||
static uint32_t buttonTimestamp = 0;
|
||||
static buttonAction_t buttonAction = BTN_INACTIVE;
|
||||
|
||||
// Check if button is pressed (LOW)
|
||||
if (digitalRead(GPIO_BUTTON) == LOW)
|
||||
{
|
||||
// Update button timestamp on the first button press
|
||||
if (buttonTimestamp == 0)
|
||||
buttonTimestamp = millis();
|
||||
|
||||
// Check and execute actions based on predefined time delays
|
||||
if (buttonTimestamp + BUTTON_ACTION_DELAY_NOTHING < millis())
|
||||
{
|
||||
LED_Process(1, COLOR_WARM_WHITE);
|
||||
buttonAction = BTN_NOTHING;
|
||||
}
|
||||
else if (buttonTimestamp + BUTTON_ACTION_DELAY_WIFI < millis())
|
||||
{
|
||||
LED_Process(1, LED_WIFI_BLINK);
|
||||
buttonAction = BTN_TOGGLEWIFI;
|
||||
}
|
||||
else if (buttonTimestamp + BUTTON_ACTION_DELAY_PURGE < millis())
|
||||
{
|
||||
LED_Process(1, LED_PURGE_COLOR);
|
||||
buttonAction = BTN_STARTPURGE;
|
||||
}
|
||||
else if (buttonTimestamp + BUTTON_ACTION_DELAY_TOGGLEMODE < millis())
|
||||
{
|
||||
uint32_t color = globals.systemStatus == sysStat_Normal ? LED_RAIN_COLOR : LED_NORMAL_COLOR;
|
||||
LED_Process(1, color);
|
||||
buttonAction = BTN_TOGGLEMODE;
|
||||
}
|
||||
}
|
||||
else // Button is released
|
||||
{
|
||||
// Execute corresponding actions based on the detected button action
|
||||
if (buttonAction != BTN_INACTIVE)
|
||||
{
|
||||
switch (buttonAction)
|
||||
{
|
||||
case BTN_TOGGLEWIFI:
|
||||
toggleWiFiAP();
|
||||
Debug_pushMessage("Starting WiFi AP\n");
|
||||
break;
|
||||
|
||||
case BTN_STARTPURGE:
|
||||
globals.systemStatus = sysStat_Purge;
|
||||
globals.purgePulses = LubeConfig.BleedingPulses;
|
||||
Debug_pushMessage("Starting Purge\n");
|
||||
break;
|
||||
|
||||
case BTN_TOGGLEMODE:
|
||||
switch (globals.systemStatus)
|
||||
{
|
||||
case sysStat_Normal:
|
||||
globals.systemStatus = sysStat_Rain;
|
||||
globals.resumeStatus = sysStat_Rain;
|
||||
break;
|
||||
|
||||
case sysStat_Rain:
|
||||
globals.systemStatus = sysStat_Normal;
|
||||
globals.resumeStatus = sysStat_Normal;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
Debug_pushMessage("Toggling Mode\n");
|
||||
break;
|
||||
|
||||
case BTN_NOTHING:
|
||||
default:
|
||||
Debug_pushMessage("Nothing or invalid\n");
|
||||
break;
|
||||
}
|
||||
|
||||
// Display feedback through LEDs
|
||||
LED_Process(2);
|
||||
}
|
||||
|
||||
// Reset button state and timestamp
|
||||
buttonAction = BTN_INACTIVE;
|
||||
buttonTimestamp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Toggles the WiFi functionality based on the current status.
|
||||
*
|
||||
@ -788,6 +477,36 @@ void SystemShutdown(bool restart)
|
||||
}
|
||||
}
|
||||
|
||||
void onToggleMode()
|
||||
{
|
||||
if (globals.systemStatus == sysStat_Normal)
|
||||
{
|
||||
globals.systemStatus = sysStat_Rain;
|
||||
globals.resumeStatus = sysStat_Rain;
|
||||
}
|
||||
else if (globals.systemStatus == sysStat_Rain)
|
||||
{
|
||||
globals.systemStatus = sysStat_Normal;
|
||||
globals.resumeStatus = sysStat_Normal;
|
||||
}
|
||||
Debug_pushMessage("Toggling Mode\n");
|
||||
}
|
||||
|
||||
void onStartPurge()
|
||||
{
|
||||
globals.systemStatus = sysStat_Purge;
|
||||
globals.purgePulses = LubeConfig.BleedingPulses;
|
||||
Debug_pushMessage("Starting Purge\n");
|
||||
}
|
||||
|
||||
|
||||
void onWashMode()
|
||||
{
|
||||
Debug_pushMessage("Wash mode start\n");
|
||||
// Hier könntest du später gezieltes Nachölen implementieren
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Processes the impulses from the wheel speed sensor and converts them into traveled distance.
|
||||
*
|
||||
|
Loading…
x
Reference in New Issue
Block a user