functions

This commit is contained in:
2026-05-25 13:49:36 -04:00
parent b5e0e5a777
commit 21938fb086
+144 -292
View File
@@ -9,6 +9,8 @@
#define SERIAL_BAUD 115200 #define SERIAL_BAUD 115200
#define MODBUS_BAUD 9600 #define MODBUS_BAUD 9600
#include <cstring>
#include <cctype>
#include <Arduino.h> #include <Arduino.h>
#include <Wire.h> #include <Wire.h>
#include <hd44780.h> #include <hd44780.h>
@@ -24,30 +26,34 @@ uint8_t modbusReadCmd[] = {0x01, 0x03, 0x00, 0x04, 0x00, 0x01};
unsigned long lastCommandTime = 0; unsigned long lastCommandTime = 0;
const unsigned long COMMAND_INTERVAL = 1000; const unsigned long COMMAND_INTERVAL = 1000;
volatile bool g_buttonInterruptFired = false; volatile bool g_buttonInterruptFired = false;
int g_waterLevelCm = -1;
void addWaterLevel();
String *descr[] = {"NA", "Pump", "Barrel -> Back Left", "Back Left -> Barrel", "Barrel to Hose", "CW to Hose", "NA", "NA"}; // String *descr[] = {"NA", "Pump", "Barrel -> Back Left", "Back Left -> Barrel", "Barrel to Hose", "CW to Hose", "NA", "NA"};
void printBin(byte aByte) void printBin(byte aByte)
{ {
for (int8_t aBit = 7; aBit >= 0; aBit--) for (int8_t aBit = 7; aBit >= 0; aBit--)
{ {
Serial.write(aBit); // Serial.print(aBit);
Serial.write(":"); // Serial.write(":");
Serial.write(bitRead(aByte, aBit) ? '1' : '0'); Serial.write(bitRead(aByte, aBit) ? '1' : '0');
Serial.write(" "); // Serial.write(" ");
} }
Serial.println(); Serial.println();
} }
// NA, Pump, Barrel -> Back Left, Back Left -> Barrel, Barrel to Hose, CW to Hose, NA, NA // NA, Pump, Barrel -> Back Left, Back Left -> Barrel, Barrel to Hose, CW to Hose, NA, NA
struct Action { struct Action
const char* name; {
const char *name;
uint8_t stat; uint8_t stat;
uint8_t mask; uint8_t mask;
bool active; bool active;
}; };
enum class ActionId : size_t { enum class ActionId : size_t
{
CityWaterToHose = 0, CityWaterToHose = 0,
BarrelToHose, BarrelToHose,
BackLeftToBarrel, BackLeftToBarrel,
@@ -57,53 +63,101 @@ enum class ActionId : size_t {
}; };
inline Action g_actions[] = { inline Action g_actions[] = {
{ "CityWaterToHose", 0b00001100, 0b00001100, false }, {"City -> Hose", 0b00001100, 0b00001100, false},
{ "BarrelToHose", 0b01000000, 0b01101100, false }, {"Barrel -> Hose", 0b01000000, 0b01101100, false},
{ "BackLeftToBarrel", 0b00010000, 0b00110000, false }, {"Back Left -> Barrel", 0b00010000, 0b00110000, false},
{ "BarrelToBackLeft", 0b01101000, 0b01111000, false }, {"Barrel -> Back Left", 0b01101000, 0b01111000, false},
{ "NotAssigned", 0b00000000, 0b00000000, false }, {"NotAssigned", 0b00000000, 0b00000000, false},
}; };
inline Action& getAction(ActionId id) { inline Action &getAction(ActionId id)
{
return g_actions[static_cast<size_t>(id)]; return g_actions[static_cast<size_t>(id)];
} }
uint8_t current_stat = 0b00000000; uint8_t current_stat = 0b00000000;
uint8_t current_mask = 0b00000000; uint8_t current_mask = 0b00000000;
bool actionCityWaterToHose = false; void updateLCDDisplay()
uint8_t statCityWaterToHose = 0b00001100;
uint8_t maskCityWaterToHose = 0b00001100;
bool actionBarrelToHose = false;
uint8_t statBarrelToHose = 0b01000000;
uint8_t maskBarrelToHose = 0b01101100;
bool actionBackLeftToBarrel = false;
uint8_t statBackLeftToBarrel = 0b00010000;
uint8_t maskBackLeftToBarrel = 0b00110000;
bool actionBarrelToBackLeft = false;
uint8_t statBarrelToBackLeft = 0b01101000;
uint8_t maskBarrelToBackLeft = 0b01111000;
bool actionNotAssigned = false;
int g_waterLevelCm = -1;
enum class ActionId
{ {
CityWaterToHose, lcd.clear();
BarrelToHose, uint8_t c_row = 0;
BackLeftToBarrel, for (size_t i = 0; i < static_cast<size_t>(ActionId::Count); ++i)
BarrelToBackLeft, {
NotAssigned, if (g_actions[i].active)
}; {
lcd.setCursor(0, c_row);
lcd.print(g_actions[i].name);
c_row++;
}
}
addWaterLevel();
}
void generateMasksByActive()
{
current_stat = 0b00000000;
current_mask = 0b00000000;
for (size_t i = 0; i < static_cast<size_t>(ActionId::Count); ++i)
{
Action &c_action = g_actions[i];
if (c_action.active)
{
current_mask = current_mask | c_action.mask;
current_stat = (current_stat & ~c_action.mask) | (c_action.stat & c_action.mask);
}
}
}
void updateStateByLastAction(ActionId LastAction) void updateStateByLastAction(ActionId LastAction)
{ {
Action &c_action = getAction(LastAction);
if (c_action.active)
{
c_action.active = false;
generateMasksByActive();
updateLCDDisplay();
return;
}
uint8_t change_stat = c_action.stat;
uint8_t change_mask = c_action.mask;
uint8_t old_stat = current_stat;
uint8_t old_mask = current_mask;
uint8_t potential_new_stat = (current_stat & ~change_mask) | (change_stat & change_mask);
uint8_t potential_old_change = (potential_new_stat ^ old_stat) & old_mask;
if (potential_old_change > 0)
{
Serial.print(c_action.name);
Serial.print(" collides with existing. Setting new mask to this one");
Serial.println();
current_stat = change_stat;
current_mask = change_mask;
for (size_t i = 0; i < static_cast<size_t>(ActionId::Count); ++i)
{
g_actions[i].active = false;
}
c_action.active = true;
}
else
{
Serial.print(c_action.name);
Serial.print(" has no collisions with existing. Setting updated mask");
Serial.println();
current_stat = potential_new_stat;
current_mask = old_mask | change_mask;
c_action.active = true;
}
Serial.print("Stat: ");
printBin(current_stat);
Serial.print("Mask: ");
printBin(current_mask);
updateLCDDisplay();
} }
void applyRelayStateIfChanged() void applyRelayStateIfChanged()
@@ -119,11 +173,6 @@ void applyRelayStateIfChanged()
Serial.print((relayValue >> bit) & 0x01); Serial.print((relayValue >> bit) & 0x01);
} }
Serial.println(); Serial.println();
// if (relayValue == lastRelayValue)
// {
// return;
// }
Wire.beginTransmission(RELAY_CONTROL_ADDRESS); Wire.beginTransmission(RELAY_CONTROL_ADDRESS);
Wire.write(relayValue); Wire.write(relayValue);
uint8_t error = Wire.endTransmission(); uint8_t error = Wire.endTransmission();
@@ -147,198 +196,60 @@ void applyRelayStateIfChanged()
} }
} }
void rebuildCurrentState() void buildTrimmedWaterLevelText(char *outBuffer, size_t outBufferSize)
{ {
current_stat = 0; if (outBuffer == nullptr || outBufferSize == 0)
current_mask = 0;
if (actionCityWaterToHose)
{
current_stat = (current_stat & ~maskCityWaterToHose) | (statCityWaterToHose & maskCityWaterToHose);
current_mask |= maskCityWaterToHose;
}
if (actionBarrelToHose)
{
current_stat = (current_stat & ~maskBarrelToHose) | (statBarrelToHose & maskBarrelToHose);
current_mask |= maskBarrelToHose;
}
if (actionBackLeftToBarrel)
{
current_stat = (current_stat & ~maskBackLeftToBarrel) | (statBackLeftToBarrel & maskBackLeftToBarrel);
current_mask |= maskBackLeftToBarrel;
}
if (actionBarrelToBackLeft)
{
current_stat = (current_stat & ~maskBarrelToBackLeft) | (statBarrelToBackLeft & maskBarrelToBackLeft);
current_mask |= maskBarrelToBackLeft;
}
applyRelayStateIfChanged();
}
void formatRightJustifiedWaterLine(char *buffer, size_t bufferSize)
{
snprintf(buffer, bufferSize, " ");
if (g_waterLevelCm < 0)
{ {
return; return;
} }
char valueText[21]; char temp[24];
snprintf(valueText, sizeof(valueText), "%d cm", g_waterLevelCm); snprintf(temp, sizeof(temp), "%d cm", g_waterLevelCm);
size_t valueLength = strlen(valueText); const char *start = temp;
size_t startColumn = valueLength < 20 ? 20 - valueLength : 0; while (*start && std::isspace(static_cast<unsigned char>(*start)))
memcpy(buffer + startColumn, valueText, min<size_t>(valueLength, 20)); {
++start;
}
const char *end = temp + strlen(temp);
while (end > start && std::isspace(static_cast<unsigned char>(*(end - 1))))
{
--end;
}
size_t len = static_cast<size_t>(end - start);
if (len >= outBufferSize)
{
len = outBufferSize - 1;
}
memcpy(outBuffer, start, len);
outBuffer[len] = '\0';
} }
void updateLcdStatesIfChanged() void addWaterLevel()
{ {
static bool lastActionCityWaterToHose = true; char text[24];
static bool lastActionBarrelToHose = true; buildTrimmedWaterLevelText(text, sizeof(text)); // e.g. "123 cm"
static bool lastActionBackLeftToBarrel = true;
static bool lastActionBarrelToBackLeft = true;
static int lastWaterLevelCm = -2;
if (lastActionCityWaterToHose == actionCityWaterToHose && size_t len = strlen(text);
lastActionBarrelToHose == actionBarrelToHose && if (len > 20)
lastActionBackLeftToBarrel == actionBackLeftToBarrel &&
lastActionBarrelToBackLeft == actionBarrelToBackLeft &&
lastWaterLevelCm == g_waterLevelCm)
{ {
return; len = 20;
text[20] = '\0';
} }
lastActionCityWaterToHose = actionCityWaterToHose; const uint8_t row = 3; // last row on 20x4
lastActionBarrelToHose = actionBarrelToHose; const uint8_t startCol = static_cast<uint8_t>(20 - len); // right-justified
lastActionBackLeftToBarrel = actionBackLeftToBarrel;
lastActionBarrelToBackLeft = actionBarrelToBackLeft;
lastWaterLevelCm = g_waterLevelCm;
lcd.clear(); // Clear row first so old characters do not remain
int lcdLine = 0; // lcd.setCursor(0, row);
// lcd.print(" "); // 20 spaces
if (actionCityWaterToHose) // Print at exact right-justified cursor position
{ lcd.setCursor(startCol, row);
lcd.setCursor(0, lcdLine++); lcd.print(text);
lcd.print("City -> Hose ");
}
if (actionBarrelToHose)
{
lcd.setCursor(0, lcdLine++);
lcd.print("Barrel -> Hose ");
}
if (actionBackLeftToBarrel)
{
lcd.setCursor(0, lcdLine++);
lcd.print("BackL -> Barrel ");
}
if (actionBarrelToBackLeft)
{
lcd.setCursor(0, lcdLine++);
lcd.print("Barrel -> BackL ");
}
while (lcdLine < 3)
{
lcd.setCursor(0, lcdLine++);
lcd.print(" ");
}
char waterLine[21];
formatRightJustifiedWaterLine(waterLine, sizeof(waterLine));
lcd.setCursor(0, 3);
lcd.print(waterLine);
}
void applyLatestAction(ActionId latestAction)
{
switch (latestAction)
{
case ActionId::CityWaterToHose:
actionCityWaterToHose = !actionCityWaterToHose;
if (actionCityWaterToHose)
{
actionBarrelToHose = false;
}
break;
case ActionId::BarrelToHose:
actionBarrelToHose = !actionBarrelToHose;
if (actionBarrelToHose)
{
actionCityWaterToHose = false;
actionBarrelToBackLeft = false;
}
break;
case ActionId::BackLeftToBarrel:
actionBackLeftToBarrel = !actionBackLeftToBarrel;
if (actionBackLeftToBarrel)
{
actionBarrelToBackLeft = false;
}
break;
case ActionId::BarrelToBackLeft:
actionBarrelToBackLeft = !actionBarrelToBackLeft;
if (actionBarrelToBackLeft)
{
actionBarrelToHose = false;
actionBackLeftToBarrel = false;
}
break;
}
// Allowed combinations:
// - CityWaterToHose + BackLeftToBarrel
// - CityWaterToHose + BarrelToBackLeft
// - BarrelToHose + BackLeftToBarrel
if (actionCityWaterToHose && actionBarrelToHose)
{
if (latestAction == ActionId::BarrelToHose)
{
actionCityWaterToHose = false;
}
else
{
actionBarrelToHose = false;
}
}
if (actionBackLeftToBarrel && actionBarrelToBackLeft)
{
if (latestAction == ActionId::BarrelToBackLeft)
{
actionBackLeftToBarrel = false;
}
else
{
actionBarrelToBackLeft = false;
}
}
if (actionBarrelToHose && actionBarrelToBackLeft)
{
if (latestAction == ActionId::BarrelToBackLeft)
{
actionBarrelToHose = false;
}
else
{
actionBarrelToBackLeft = false;
}
}
rebuildCurrentState();
} }
void IRAM_ATTR onButtonInterrupt() void IRAM_ATTR onButtonInterrupt()
@@ -411,8 +322,7 @@ void readAndPrintButtons()
bool buttonP6Pressed = (portValue & (1 << 6)) == 0; bool buttonP6Pressed = (portValue & (1 << 6)) == 0;
bool buttonP7Pressed = (portValue & (1 << 7)) == 0; bool buttonP7Pressed = (portValue & (1 << 7)) == 0;
printBin(portValue); ActionId LastAction = ActionId::Count;
ActionId LastAction;
if (buttonP3Pressed) if (buttonP3Pressed)
{ {
@@ -432,7 +342,7 @@ void readAndPrintButtons()
} }
else if (buttonP7Pressed) else if (buttonP7Pressed)
{ {
LastAction = ActionId::NotAssigned; // LastAction = ActionId::NotAssigned;
} }
Serial.printf( Serial.printf(
@@ -443,73 +353,14 @@ void readAndPrintButtons()
buttonP6Pressed, buttonP6Pressed,
buttonP7Pressed, buttonP7Pressed,
portValue); portValue);
if (LastAction != ActionId::Count)
{
updateStateByLastAction(LastAction);
}
} }
} }
// void readAndPrintButtons()
// {
// // PCF8574 button wiring:
// // - P0 is the shared/common line and must be driven LOW.
// // - P3..P7 are button sense lines. Pressed => line pulled LOW (active-low).
// Wire.beginTransmission(BUTTONS_CONTROL_ADDRESS);
// Wire.write(0b11111110); // P0 LOW, all other pins released HIGH.
// Wire.endTransmission();
// Wire.requestFrom(BUTTONS_CONTROL_ADDRESS, (uint8_t)1);
// if (Wire.available())
// {
// uint8_t portValue = Wire.read();
// bool buttonP3Pressed = (portValue & (1 << 3)) == 0;
// bool buttonP4Pressed = (portValue & (1 << 4)) == 0;
// bool buttonP5Pressed = (portValue & (1 << 5)) == 0;
// bool buttonP6Pressed = (portValue & (1 << 6)) == 0;
// bool buttonP7Pressed = (portValue & (1 << 7)) == 0;
// if (buttonP3Pressed && !buttonP4Pressed)
// {
// applyLatestAction(ActionId::CityWaterToHose);
// }
// if (buttonP4Pressed && !buttonP3Pressed)
// {
// applyLatestAction(ActionId::BarrelToHose);
// }
// if (buttonP5Pressed)
// {
// applyLatestAction(ActionId::BackLeftToBarrel);
// }
// if (buttonP6Pressed)
// {
// applyLatestAction(ActionId::BarrelToBackLeft);
// }
// if (buttonP7Pressed)
// {
// actionNotAssigned = !actionNotAssigned;
// }
// Serial.printf(
// "INT Buttons P3=%d P4=%d P5=%d P6=%d P7=%d (raw=0x%02X)\n",
// buttonP3Pressed,
// buttonP4Pressed,
// buttonP5Pressed,
// buttonP6Pressed,
// buttonP7Pressed,
// portValue);
// Serial.printf(
// "States CityWaterToHose=%d BarrelToHose=%d BackLeftToBarrel=%d BarrelToBackLeft=%d current_stat=0x%02X current_mask=0x%02X\n",
// actionCityWaterToHose,
// actionBarrelToHose,
// actionBackLeftToBarrel,
// actionBarrelToBackLeft,
// current_stat,
// current_mask);
// }
// }
void pollSerial2WaterLevel() void pollSerial2WaterLevel()
{ {
static uint8_t responseBuffer[256]; static uint8_t responseBuffer[256];
@@ -540,6 +391,7 @@ void pollSerial2WaterLevel()
{ {
lastPrintedWaterLevelCm = waterLevelCm; lastPrintedWaterLevelCm = waterLevelCm;
g_waterLevelCm = waterLevelCm; g_waterLevelCm = waterLevelCm;
addWaterLevel();
Serial.printf("Water level: %d cm (%d mm)\n", waterLevelCm, data); Serial.printf("Water level: %d cm (%d mm)\n", waterLevelCm, data);
} }
} }
@@ -577,7 +429,7 @@ void setup()
int lcdStatus = lcd.begin(20, 4); int lcdStatus = lcd.begin(20, 4);
lcd.clear(); lcd.clear();
updateLcdStatesIfChanged(); // updateLcdStatesIfChanged();
Serial2.begin(MODBUS_BAUD, SERIAL_8N1, RXD_PIN, TXD_PIN); Serial2.begin(MODBUS_BAUD, SERIAL_8N1, RXD_PIN, TXD_PIN);
start = millis(); start = millis();
@@ -603,6 +455,6 @@ void loop()
lastSerial2PollTime = millis(); lastSerial2PollTime = millis();
pollSerial2WaterLevel(); pollSerial2WaterLevel();
} }
updateLcdStatesIfChanged(); // updateLcdStatesIfChanged();
delay(10); delay(10);
} }