From ba6c0ed2f2faf8831b968115b96b81de9febbdea Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Fri, 24 Oct 2025 17:32:47 -0400 Subject: [PATCH 01/21] 273: Initial work to migrate GPAD_API to PlatformIO - Necessary libraries have been added and are tracked in the 'platform.ini' file --- Firmware/GPAD_API/.gitignore | 6 + Firmware/GPAD_API/GPAD_menu.cpp | 126 ---------- Firmware/GPAD_API/include/README | 37 +++ Firmware/GPAD_API/lib/README | 46 ++++ Firmware/GPAD_API/platformio.ini | 27 ++ Firmware/GPAD_API/{ => src}/DFPlayer.cpp | 0 Firmware/GPAD_API/{ => src}/DFPlayer.h | 0 Firmware/GPAD_API/{ => src}/GPAD_API.ino | 236 ++++++++++-------- Firmware/GPAD_API/{ => src}/GPAD_HAL.cpp | 0 Firmware/GPAD_API/{ => src}/GPAD_HAL.h | 54 ++-- Firmware/GPAD_API/src/GPAD_menu.cpp | 129 ++++++++++ Firmware/GPAD_API/{ => src}/GPAD_menu.h | 0 .../GPAD_API/{ => src}/InterruptRotator.cpp | 0 .../GPAD_API/{ => src}/InterruptRotator.h | 0 Firmware/GPAD_API/{ => src}/README.md | 0 .../{ => src}/RickmanLiquidCrystal_I2C.h | 0 .../GPAD_API/{ => src}/WiFiManagerOTA.cpp | 0 Firmware/GPAD_API/{ => src}/WiFiManagerOTA.h | 0 Firmware/GPAD_API/{ => src}/Wink.cpp | 0 Firmware/GPAD_API/{ => src}/Wink.h | 0 Firmware/GPAD_API/{ => src}/alarm_api.cpp | 0 Firmware/GPAD_API/{ => src}/alarm_api.h | 0 Firmware/GPAD_API/{ => src}/data/favicon.png | Bin Firmware/GPAD_API/{ => src}/data/index.html | 0 Firmware/GPAD_API/{ => src}/data/style.css | 0 Firmware/GPAD_API/{ => src}/gpad_serial.cpp | 0 Firmware/GPAD_API/{ => src}/gpad_serial.h | 0 Firmware/GPAD_API/{ => src}/gpad_utility.cpp | 0 Firmware/GPAD_API/{ => src}/gpad_utility.h | 0 Firmware/GPAD_API/test/README | 11 + 30 files changed, 407 insertions(+), 265 deletions(-) create mode 100644 Firmware/GPAD_API/.gitignore delete mode 100644 Firmware/GPAD_API/GPAD_menu.cpp create mode 100644 Firmware/GPAD_API/include/README create mode 100644 Firmware/GPAD_API/lib/README create mode 100644 Firmware/GPAD_API/platformio.ini rename Firmware/GPAD_API/{ => src}/DFPlayer.cpp (100%) rename Firmware/GPAD_API/{ => src}/DFPlayer.h (100%) rename Firmware/GPAD_API/{ => src}/GPAD_API.ino (77%) rename Firmware/GPAD_API/{ => src}/GPAD_HAL.cpp (100%) rename Firmware/GPAD_API/{ => src}/GPAD_HAL.h (73%) create mode 100644 Firmware/GPAD_API/src/GPAD_menu.cpp rename Firmware/GPAD_API/{ => src}/GPAD_menu.h (100%) rename Firmware/GPAD_API/{ => src}/InterruptRotator.cpp (100%) rename Firmware/GPAD_API/{ => src}/InterruptRotator.h (100%) rename Firmware/GPAD_API/{ => src}/README.md (100%) rename Firmware/GPAD_API/{ => src}/RickmanLiquidCrystal_I2C.h (100%) rename Firmware/GPAD_API/{ => src}/WiFiManagerOTA.cpp (100%) rename Firmware/GPAD_API/{ => src}/WiFiManagerOTA.h (100%) rename Firmware/GPAD_API/{ => src}/Wink.cpp (100%) rename Firmware/GPAD_API/{ => src}/Wink.h (100%) rename Firmware/GPAD_API/{ => src}/alarm_api.cpp (100%) rename Firmware/GPAD_API/{ => src}/alarm_api.h (100%) rename Firmware/GPAD_API/{ => src}/data/favicon.png (100%) rename Firmware/GPAD_API/{ => src}/data/index.html (100%) rename Firmware/GPAD_API/{ => src}/data/style.css (100%) rename Firmware/GPAD_API/{ => src}/gpad_serial.cpp (100%) rename Firmware/GPAD_API/{ => src}/gpad_serial.h (100%) rename Firmware/GPAD_API/{ => src}/gpad_utility.cpp (100%) rename Firmware/GPAD_API/{ => src}/gpad_utility.h (100%) create mode 100644 Firmware/GPAD_API/test/README diff --git a/Firmware/GPAD_API/.gitignore b/Firmware/GPAD_API/.gitignore new file mode 100644 index 00000000..d71a84bf --- /dev/null +++ b/Firmware/GPAD_API/.gitignore @@ -0,0 +1,6 @@ +.pio +.vscode/.browse.c_cpp.db* +.vscode/c_cpp_properties.json +.vscode/launch.json +.vscode/ipch +compile_commands.json diff --git a/Firmware/GPAD_API/GPAD_menu.cpp b/Firmware/GPAD_API/GPAD_menu.cpp deleted file mode 100644 index 12bc8d11..00000000 --- a/Firmware/GPAD_API/GPAD_menu.cpp +++ /dev/null @@ -1,126 +0,0 @@ -#include -#include -#include -#include -#include -#include "GPAD_hal.h" -#include "RickmanLiquidCrystal_I2C.h" -#include "DFPlayer.h" - -using namespace Menu; - -extern bool running_menu; -extern bool menu_just_exited; - -#define LEDPIN 12 -#define MAX_DEPTH 1 - -// This needs to be cleaned up; the PubSublcient and WiFi stuff needs to put into a -// a module that is not in GPAD_API.ino -extern PubSubClient client; -extern char publish_Ack_Topic[17]; - -result action1(eventMask e) { - if (e == eventMask::enterEvent) { - Serial.println(F("Yes, I will take that action #1 !")); - } - char onLineMsg[32] = "Acknowledging!"; - client.publish(publish_Ack_Topic, onLineMsg); - Serial.print("Messgage sent to topic: "); - Serial.println(publish_Ack_Topic); - return proceed; -} -result action2(eventMask e) { - if (e == eventMask::enterEvent) { - Serial.println(F("Yes, I will take that action #2 !")); - } - return proceed; -} -result action3(eventMask e) { - if (e == eventMask::enterEvent) { - Serial.println(F("Yes, I will take that action #3 !")); - } - return proceed; -} -result action4(eventMask e) { - if (e == eventMask::enterEvent) { - Serial.println(F("Yes, I will take that action #3 !")); - } - Serial.print(F("volume value: ")); - Serial.println(volumeDFPlayer); - setVolume(volumeDFPlayer); - return proceed; -} -result action5(eventMask e) { - Serial.println("exiting menu"); - running_menu = false; - menu_just_exited = true; - Menu::doExit(); - return proceed; -} - - -MENU(mainMenu, "Krake Menu", Menu::doNothing, Menu::noEvent, Menu::wrapStyle - ,OP("Acknowledge",action1,anyEvent) - ,OP("Dismiss",action2,anyEvent) - ,OP("Shelve",action3,anyEvent) - ,FIELD(volumeDFPlayer,"Volume","%",0,30,10,1,action4,anyEvent,wrapStyle) - ,OP("Exit Menu", action5, enterEvent) - ); - -RotaryEventIn reIn( - RotaryEventIn::EventType::BUTTON_CLICKED | // select - RotaryEventIn::EventType::BUTTON_DOUBLE_CLICKED | // back - RotaryEventIn::EventType::BUTTON_LONG_PRESSED | // also back - RotaryEventIn::EventType::ROTARY_CCW | // up - RotaryEventIn::EventType::ROTARY_CW // down -); // register capabilities, see AndroidMenu MenuIO/RotaryEventIn.h file -MENU_INPUTS(in,&reIn); - -// serialIn serial(Serial); -// MENU_INPUTS(in,&serial); - - -MENU_OUTPUTS(out,MAX_DEPTH -// ,SERIAL_OUT(Serial) - ,LCD_OUT(lcd,{0,0,20,4}) - ,NONE//must have 2 items at least -); - -NAVROOT(nav,mainMenu,MAX_DEPTH,in,out); - - -void registerRotationEvent(bool CW) { - Serial.print("CW: "); - Serial.println(CW); - // Note: Rob believes it is more "natural" for clockwise to mean "up". - // Apparently, whoever wrote the "MENU_INPUTS" believes the opposite, - // so I am changing this hear to reverse the sense. - reIn.registerEvent(CW ? RotaryEventIn::EventType::ROTARY_CCW - : RotaryEventIn::EventType::ROTARY_CW); -} - -void registerRotaryEncoderPress() { - reIn.registerEvent(RotaryEventIn::EventType::BUTTON_CLICKED); -} - - -void setup_GPAD_menu() { - -} - - -void poll_GPAD_menu() { - nav.poll(); -} - -void navigate_to_n_and_execute(int n) { - Serial.println("moving to zero and executing!"); - nav.doNav(navCmd(idxCmd,n)); //hilite second option - //nav.doNav(navCmd(enterCmd)); //execute option -} - -void reset_menu_navigation() { - running_menu = true; - nav.reset(); - } diff --git a/Firmware/GPAD_API/include/README b/Firmware/GPAD_API/include/README new file mode 100644 index 00000000..49819c0d --- /dev/null +++ b/Firmware/GPAD_API/include/README @@ -0,0 +1,37 @@ + +This directory is intended for project header files. + +A header file is a file containing C declarations and macro definitions +to be shared between several project source files. You request the use of a +header file in your project source file (C, C++, etc) located in `src` folder +by including it, with the C preprocessing directive `#include'. + +```src/main.c + +#include "header.h" + +int main (void) +{ + ... +} +``` + +Including a header file produces the same results as copying the header file +into each source file that needs it. Such copying would be time-consuming +and error-prone. With a header file, the related declarations appear +in only one place. If they need to be changed, they can be changed in one +place, and programs that include the header file will automatically use the +new version when next recompiled. The header file eliminates the labor of +finding and changing all the copies as well as the risk that a failure to +find one copy will result in inconsistencies within a program. + +In C, the convention is to give header files names that end with `.h'. + +Read more about using header files in official GCC documentation: + +* Include Syntax +* Include Operation +* Once-Only Headers +* Computed Includes + +https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html diff --git a/Firmware/GPAD_API/lib/README b/Firmware/GPAD_API/lib/README new file mode 100644 index 00000000..93793971 --- /dev/null +++ b/Firmware/GPAD_API/lib/README @@ -0,0 +1,46 @@ + +This directory is intended for project specific (private) libraries. +PlatformIO will compile them to static libraries and link into the executable file. + +The source code of each library should be placed in a separate directory +("lib/your_library_name/[Code]"). + +For example, see the structure of the following example libraries `Foo` and `Bar`: + +|--lib +| | +| |--Bar +| | |--docs +| | |--examples +| | |--src +| | |- Bar.c +| | |- Bar.h +| | |- library.json (optional. for custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html +| | +| |--Foo +| | |- Foo.c +| | |- Foo.h +| | +| |- README --> THIS FILE +| +|- platformio.ini +|--src + |- main.c + +Example contents of `src/main.c` using Foo and Bar: +``` +#include +#include + +int main (void) +{ + ... +} + +``` + +The PlatformIO Library Dependency Finder will find automatically dependent +libraries by scanning project source files. + +More information about PlatformIO Library Dependency Finder +- https://docs.platformio.org/page/librarymanager/ldf.html diff --git a/Firmware/GPAD_API/platformio.ini b/Firmware/GPAD_API/platformio.ini new file mode 100644 index 00000000..9050cb5b --- /dev/null +++ b/Firmware/GPAD_API/platformio.ini @@ -0,0 +1,27 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[env:esp32dev] +build_flags = + -DELEGANTOTA_USE_ASYNC_WEBSERVER=1 +platform = espressif32 +board = esp32dev +framework = arduino +lib_extra_dirs = ~/Documents/Arduino/libraries +lib_deps = + mathertel/RotaryEncoder@^1.5.3 + knolleary/PubSubClient@^2.8 + neu-rah/ArduinoMenu library@^4.21.5 + cygig/DailyStruggleButton@^0.5.1 + neu-rah/streamFlow@0.0.0-alpha+sha.bf16ce8926 + tzapu/WiFiManager@^2.0.17 + ayushsharma82/ElegantOTA@^3.1.7 + marcoschwartz/LiquidCrystal_I2C@^1.1.4 + dfrobot/DFRobotDFPlayerMini@^1.0.6 diff --git a/Firmware/GPAD_API/DFPlayer.cpp b/Firmware/GPAD_API/src/DFPlayer.cpp similarity index 100% rename from Firmware/GPAD_API/DFPlayer.cpp rename to Firmware/GPAD_API/src/DFPlayer.cpp diff --git a/Firmware/GPAD_API/DFPlayer.h b/Firmware/GPAD_API/src/DFPlayer.h similarity index 100% rename from Firmware/GPAD_API/DFPlayer.h rename to Firmware/GPAD_API/src/DFPlayer.h diff --git a/Firmware/GPAD_API/GPAD_API.ino b/Firmware/GPAD_API/src/GPAD_API.ino similarity index 77% rename from Firmware/GPAD_API/GPAD_API.ino rename to Firmware/GPAD_API/src/GPAD_API.ino index a8cfa37b..7b434dc6 100644 --- a/Firmware/GPAD_API/GPAD_API.ino +++ b/Firmware/GPAD_API/src/GPAD_API.ino @@ -54,19 +54,19 @@ #include "GPAD_HAL.h" #include "gpad_utility.h" #include "gpad_serial.h" -#include "wink.h" -#include +#include "Wink.h" +#include #include #include -#include // From library https://github.com/knolleary/ +#include // From library https://github.com/knolleary/ -#include // WiFi Manager for ESP32 +#include // WiFi Manager for ESP32 #include "LittleFS.h" #include -#include // File System Support -#include // req for i2c comm +#include // File System Support +#include // req for i2c comm #include "WiFiManagerOTA.h" #include @@ -76,7 +76,6 @@ #include "DFPlayer.h" #include "GPAD_menu.h" - AsyncWebServer server(80); AsyncWebSocket ws("/ws"); @@ -84,7 +83,6 @@ AsyncWebSocket ws("/ws"); WiFiClient espClient; PubSubClient client(espClient); - /* SPI_PERIPHERAL From: https://circuitdigest.com/microcontroller-projects/arduino-spi-communication-tutorial Modified by Forrest Lee Erickson 20220523 @@ -99,9 +97,9 @@ PubSubClient client(espClient); 20220927 Change back for GPAD nCS on Pin 10 */ -//SPI PERIPHERAL (ARDUINO UNO) -//SPI COMMUNICATION BETWEEN TWO ARDUINO UNOs -//CIRCUIT DIGEST +// SPI PERIPHERAL (ARDUINO UNO) +// SPI COMMUNICATION BETWEEN TWO ARDUINO UNOs +// CIRCUIT DIGEST /* Hardware Notes Peripheral SPI Line Pin in Arduino, IO setup @@ -113,12 +111,11 @@ PubSubClient client(espClient); #define GPAD_VERSION1 - #define DEBUG_SPI 0 -//#define DEBUG 0 +// #define DEBUG 0 #define DEBUG 1 -//#define DEBUG 4 +// #define DEBUG 4 unsigned long last_command_ms; @@ -127,32 +124,31 @@ unsigned long last_command_ms; const unsigned long DELAY_BEFORE_NEW_COMMAND_ALLOWED = 10000; const unsigned int NUM_WIFI_RECONNECT_RETRIES = 3; -const int LED_PINS[] = { LIGHT0, LIGHT1, LIGHT2, LIGHT3, LIGHT4 }; +const int LED_PINS[] = {LIGHT0, LIGHT1, LIGHT2, LIGHT3, LIGHT4}; // const int SWITCH_PINS[] = { SW1, SW2, SW3, SW4 }; // SW1, SW2, SW3, SW4 const int LED_COUNT = sizeof(LED_PINS) / sizeof(LED_PINS[0]); // const int SWITCH_COUNT = sizeof(SWITCH_PINS) / sizeof(SWITCH_PINS[0]); -//Aley network -// const char* ssid = "Home"; -// const char* password = "adt@1963#"; +// Aley network +// const char* ssid = "Home"; +// const char* password = "adt@1963#"; -//Maryville network -// const char* ssid = "VRX"; -// const char* password = "textinsert"; +// Maryville network +// const char* ssid = "VRX"; +// const char* password = "textinsert"; -//Houstin network -// const char* ssid = "DOS_WIFI"; -// const char* password = "$Suve07$$"; +// Houstin network +// const char* ssid = "DOS_WIFI"; +// const char* password = "$Suve07$$"; // Austin network -const char* ssid = "readfamilynetwork"; -const char* password = "magicalsparrow96"; - +const char *ssid = "readfamilynetwork"; +const char *password = "magicalsparrow96"; // MQTT Broker -const char* mqtt_broker_name = "public.cloud.shiftr.io"; -const char* mqtt_user = "public"; -const char* mqtt_password = "public"; +const char *mqtt_broker_name = "public.cloud.shiftr.io"; +const char *mqtt_user = "public"; +const char *mqtt_password = "public"; // MQTT Topics, MAC plus an extention // A MAC addresss treated as a string has 12 chars. @@ -180,18 +176,19 @@ char macAddressString[13]; // #define SERIAL_TIMEOUT_MS 600000 #define SERIAL_TIMEOUT_MS 1000 -//Set LED wink parameters -const int HIGH_TIME_LED_MS = 800; //time in milliseconds +// Set LED wink parameters +const int HIGH_TIME_LED_MS = 800; // time in milliseconds const int LOW_TIME_LED_MS = 200; unsigned long lastLEDtime_ms = 0; // unsigned long nextLEDchangee_ms = 100; //time in ms. -unsigned long nextLEDchangee_ms = 5000; //time in ms. +unsigned long nextLEDchangee_ms = 5000; // time in ms. // extern int LIGHT[]; // extern int NUM_LIGHTS; -void serialSplash() { - //Serial splash +void serialSplash() +{ + // Serial splash Serial.println(F("===================================")); Serial.println(COMPANY_NAME); Serial.println(MODEL_NAME); @@ -206,18 +203,20 @@ void serialSplash() { Serial.print(F("Broker: ")); Serial.println(mqtt_broker_name); Serial.print(F("Compiled at: ")); - Serial.println(F(__DATE__ " " __TIME__)); //compile date that is used for a unique identifier + Serial.println(F(__DATE__ " " __TIME__)); // compile date that is used for a unique identifier Serial.println(LICENSE); Serial.println(F("===================================")); Serial.println(); } // A periodic message identifying the subscriber (Krake) is on line. -void publishOnLineMsg(void) { +void publishOnLineMsg(void) +{ const unsigned long MESSAGE_PERIOD = 10000; - static unsigned long lastMillis = 0; // Sets timing for periodic MQTT publish message + static unsigned long lastMillis = 0; // Sets timing for periodic MQTT publish message // publish a message roughly every second. - if ((millis() - lastMillis > MESSAGE_PERIOD) || (millis() < lastMillis)) { //Check for role over. + if ((millis() - lastMillis > MESSAGE_PERIOD) || (millis() < lastMillis)) + { // Check for role over. lastMillis = lastMillis + MESSAGE_PERIOD; float rssi = WiFi.RSSI(); @@ -238,15 +237,15 @@ void publishOnLineMsg(void) { // Serial.println(WiFi.localIP()); //FLE #if defined(HMWK) - digitalWrite(LED_D9, !digitalRead(LED_D9)); // Toggle + digitalWrite(LED_D9, !digitalRead(LED_D9)); // Toggle #endif } } - - -bool connect_to_wifi() { - if (WiFi.status() != WL_CONNECTED) { +bool connect_to_wifi() +{ + if (WiFi.status() != WL_CONNECTED) + { delay(10); Serial.println(); @@ -254,34 +253,42 @@ bool connect_to_wifi() { Serial.println(ssid); WiFi.begin(ssid, password); - if (WiFi.status() != WL_CONNECTED) { + if (WiFi.status() != WL_CONNECTED) + { Serial.println("Failed to connect WiFi."); return false; - } else { + } + else + { Serial.print("WiFi connected"); #if (DEBUG > 1) delay(100); - Serial.print("Device connected at IPaddress: "); //FLE - Serial.println(WiFi.localIP()); //FLE + Serial.print("Device connected at IPaddress: "); // FLE + Serial.println(WiFi.localIP()); // FLE #endif return true; } } return true; -} // end connect_to_wifi() +} // end connect_to_wifi() // TODO: have this return a success or failure status and move // the delay up. -void reconnect() { +void reconnect() +{ int n = 0; - while (!client.connected() && n < NUM_WIFI_RECONNECT_RETRIES) { + while (!client.connected() && n < NUM_WIFI_RECONNECT_RETRIES) + { n++; Serial.print("Attempting MQTT connection..."); - if (client.connect(COMPANY_NAME, mqtt_user, mqtt_password)) { + if (client.connect(COMPANY_NAME, mqtt_user, mqtt_password)) + { Serial.println("success!"); - client.subscribe(subscribe_Alarm_Topic); // Subscribe to GPAD API alarms - } else { + client.subscribe(subscribe_Alarm_Topic); // Subscribe to GPAD API alarms + } + else + { Serial.print("failed, rc="); Serial.print(client.state()); delay(1000); @@ -290,7 +297,8 @@ void reconnect() { Serial.println((client.connected()) ? "connected!" : "failed to reconnect!"); } // Function to turn on all lamps -void turnOnAllLamps() { +void turnOnAllLamps() +{ #if defined(HMWK) digitalWrite(LED_D9, HIGH); #endif @@ -300,7 +308,8 @@ void turnOnAllLamps() { digitalWrite(LIGHT3, HIGH); digitalWrite(LIGHT4, HIGH); } -void turnOffAllLamps() { +void turnOffAllLamps() +{ #if defined(HMWK) digitalWrite(LED_D9, LOW); #endif @@ -311,21 +320,22 @@ void turnOffAllLamps() { digitalWrite(LIGHT4, LOW); } - - // Handeler for MQTT subscribed messages -void callback(char* topic, byte* payload, unsigned int length) { +void callback(char *topic, byte *payload, unsigned int length) +{ // todo, remove use of String here.... // Note: We will check for topic or topics in the future... - if (strcmp(topic, subscribe_Alarm_Topic) == 0) { + if (strcmp(topic, subscribe_Alarm_Topic) == 0) + { char mbuff[121]; Serial.print("Topic arrived ["); Serial.print(topic); Serial.print("] "); - //Put payload into mbuff[] a character array + // Put payload into mbuff[] a character array int m = min((unsigned int)length, (unsigned int)120); - for (int i = 0; i < m; i++) { + for (int i = 0; i < m; i++) + { mbuff[i] = (char)payload[i]; } mbuff[m] = '\0'; @@ -337,49 +347,53 @@ void callback(char* topic, byte* payload, unsigned int length) { #endif Serial.println("Received MQTT Msg."); - interpretBuffer(mbuff, m, &Serial, &client); //Process the MQTT message + interpretBuffer(mbuff, m, &Serial, &client); // Process the MQTT message annunciateAlarmLevel(&Serial); } -} //end call back +} // end call back -bool readMacAddress(uint8_t* baseMac) { +bool readMacAddress(uint8_t *baseMac) +{ // uint8_t baseMac[6]; esp_err_t ret = esp_wifi_get_mac(WIFI_IF_STA, baseMac); - if (ret == ESP_OK) { + if (ret == ESP_OK) + { // Serial.printf("%02x:%02x:%02x:%02x:%02x:%02x\n", // baseMac[0], baseMac[1], baseMac[2], // baseMac[3], baseMac[4], baseMac[5]); return true; - } else { + } + else + { // Serial.println("Failed to read MAC address"); return false; } } -//Elegant OTA Setup +// Elegant OTA Setup -void setupOTA() { +void setupOTA() +{ // Route for root / web page - server.on("/", HTTP_GET, [](AsyncWebServerRequest* request) { - request->send(LittleFS, "/index.html", "text/html", false, processor); - }); + server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) + { request->send(LittleFS, "/index.html", "text/html", false, processor); }); server.serveStatic("/", LittleFS, "/"); - // End of ELegant OTA Setup } - -void setup() { - pinMode(LED_BUILTIN, OUTPUT); // set the LED pin mode +void setup() +{ + pinMode(LED_BUILTIN, OUTPUT); // set the LED pin mode digitalWrite(LED_BUILTIN, HIGH); - //Serial setup + // Serial setup delay(100); Serial.begin(BAUDRATE); - while (!Serial) { - ; // wait for serial port to connect. Needed for native USB + while (!Serial) + { + ; // wait for serial port to connect. Needed for native USB } serialSplash(); // We call this a second time to get the MAC on the screen @@ -398,7 +412,7 @@ void setup() { // Turn off all LEDs initially turnOnAllLamps(); - //Init arrays. + // Init arrays. subscribe_Alarm_Topic[0] = '\0'; publish_Ack_Topic[0] = '\0'; macAddressString[0] = '\0'; @@ -407,9 +421,9 @@ void setup() { Serial.println("Call: GPAD_HAL_setup(&Serial)"); #endif - //Setup and present LCD splash screen - //Setup the SWITCH_MUTE - //Setup the SWITCH_ENCODER + // Setup and present LCD splash screen + // Setup the SWITCH_MUTE + // Setup the SWITCH_ENCODER GPAD_HAL_setup(&Serial); #if (DEBUG > 0) @@ -418,14 +432,13 @@ void setup() { #endif Serial.setTimeout(SERIAL_TIMEOUT_MS); - client.setServer(mqtt_broker_name, 1883); //Default MQTT port + client.setServer(mqtt_broker_name, 1883); // Default MQTT port client.setCallback(callback); #if (DEBUG > 0) Serial.println("Starting WiFi as STA"); #endif - // Note: On Krake SN#3 only, performing this // while the Splash is on causes a reset, presumably // because too much power is drawn. I am using a conditional @@ -438,7 +451,6 @@ void setup() { #endif WiFi.mode(WIFI_STA); - WiFi.STA.begin(); #if (LIMIT_POWER_DRAW) splashLCD(); @@ -478,76 +490,78 @@ void setup() { // req for Wifi Man and OTA WiFiMan(); initLittleFS(); - server.begin(); // Start server web socket to render pages + server.begin(); // Start server web socket to render pages ElegantOTA.begin(&server); setupOTA(); // Need this to work here: printInstructions(serialport); Serial.println(F("Done With Setup!")); turnOnAllLamps(); - digitalWrite(LED_BUILTIN, LOW); // turn the LED off at end of setup + digitalWrite(LED_BUILTIN, LOW); // turn the LED off at end of setup initRotator(); splashLCD(); + setupDFPlayer(); + setup_GPAD_menu(); - setupDFPlayer(); - setup_GPAD_menu(); - -} // end of setup() +} // end of setup() unsigned long last_ms = 0; -void toggle(int pin) { +void toggle(int pin) +{ digitalWrite(pin, digitalRead(pin) ? LOW : HIGH); } const unsigned long LOW_FREQ_DEBUG_MS = 20000; unsigned long time_since_LOW_FREQ_ms = 0; -//IPAddress myIP(0, 0, 0, 0); // declare for global and initialize -IPAddress myIP(); // declare for global +// IPAddress myIP(0, 0, 0, 0); // declare for global and initialize +IPAddress myIP(); // declare for global int cnt_actions = 0; bool running_menu = false; bool menu_just_exited = false; -void loop() { +void loop() +{ bool is_WIFIconnected = false; unsigned long ms = millis(); - if (ms - time_since_LOW_FREQ_ms > LOW_FREQ_DEBUG_MS) { + if (ms - time_since_LOW_FREQ_ms > LOW_FREQ_DEBUG_MS) + { time_since_LOW_FREQ_ms = ms; - //If WiFi was not connected and becomes connected then print IP address - if (!is_WIFIconnected && connect_to_wifi()) { + // If WiFi was not connected and becomes connected then print IP address + if (!is_WIFIconnected && connect_to_wifi()) + { is_WIFIconnected = true; - //Get the IP address into a variable I can make global + // Get the IP address into a variable I can make global IPAddress myIP = WiFi.localIP(); - const char* ipString = myIP.toString().c_str(); + const char *ipString = myIP.toString().c_str(); // strcat(onInfoMsg, *getCurrentMessage()); Produced error error: invalid conversion from 'char' to 'const char*' [-fpermissive] - Serial.print("Device connected at IPaddress: "); //FLE - // Serial.println(WiFi.localIP()); //FLE - Serial.println(myIP); //FLE + Serial.print("Device connected at IPaddress: "); // FLE + // Serial.println(WiFi.localIP()); //FLE + Serial.println(myIP); // FLE } - // Serial.println(subscribe_Alarm_Topic); // Serial.println(publish_Ack_Topic); #if defined HMWK || defined KRAKE - if (!client.connected()) { + if (!client.connected()) + { reconnect(); } #endif } - #if defined HMWK || defined KRAKE client.loop(); publishOnLineMsg(); - wink(); //The builtin LED + wink(); // The builtin LED #endif unchanged_anunicateAlarmLevel(&Serial); @@ -568,13 +582,15 @@ void loop() { updateRotator(); - if (menu_just_exited) { + if (menu_just_exited) + { lcd.clear(); lcd.noBacklight(); restoreAlarmLevel(&Serial); menu_just_exited = false; } - if (running_menu) { + if (running_menu) + { lcd.backlight(); poll_GPAD_menu(); } diff --git a/Firmware/GPAD_API/GPAD_HAL.cpp b/Firmware/GPAD_API/src/GPAD_HAL.cpp similarity index 100% rename from Firmware/GPAD_API/GPAD_HAL.cpp rename to Firmware/GPAD_API/src/GPAD_HAL.cpp diff --git a/Firmware/GPAD_API/GPAD_HAL.h b/Firmware/GPAD_API/src/GPAD_HAL.h similarity index 73% rename from Firmware/GPAD_API/GPAD_HAL.h rename to Firmware/GPAD_API/src/GPAD_HAL.h index 70c15a44..d8baef2f 100644 --- a/Firmware/GPAD_API/GPAD_HAL.h +++ b/Firmware/GPAD_API/src/GPAD_HAL.h @@ -18,12 +18,11 @@ */ - #ifndef GPAD_HAL #define GPAD_HAL 1 -#include -//#include -#include +#include +// #include +#include #include // On Nov. 5th, 2024, we image 3 different hardware platforms. @@ -34,32 +33,32 @@ // Define only ONE of these hardware options. // #define GPAD 1 -//#define HMWK 1 +// #define HMWK 1 #define KRAKE 1 // Use these to choose the I2C address of LCD // GPAD device (earlier version of the Krake) -#define LCD_ADDRESS 0x38 +#define LCD_ADDRESS 0x38 // Maryville version and Austin version -// #define LCD_ADDRESS 0x27 +// #define LCD_ADDRESS 0x27 // General (Lebanon) Version -// #define LCD_ADDRESS 0x3F +// #define LCD_ADDRESS 0x3F -//Pin definitions. Assign symbolic constant to Arduino pin numbers. -//For more information see: https://www.arduino.cc/en/Tutorial/Foundations/DigitalPins -// This should be done with an "#elif", but I can't get it to work +// Pin definitions. Assign symbolic constant to Arduino pin numbers. +// For more information see: https://www.arduino.cc/en/Tutorial/Foundations/DigitalPins +// This should be done with an "#elif", but I can't get it to work #if defined(KRAKE) #define SWITCH_MUTE 35 -//#define TONE_PIN 8 +// #define TONE_PIN 8 #define LIGHT0 12 #define LIGHT1 14 #define LIGHT2 27 #define LIGHT3 26 #define LIGHT4 25 #define LED_BUILTIN 13 -#define SWITCH_ENCODER 34 //Center switch aka button Normaly high. +#define SWITCH_ENCODER 34 // Center switch aka button Normaly high. #endif #if defined(GPAD) @@ -77,8 +76,8 @@ // This should be done with an "#elif", but I can't get it to work #if defined(HMWK) -//#define SWITCH_MUTE 34 -#define SWITCH_MUTE 0 //Boot button +// #define SWITCH_MUTE 34 +#define SWITCH_MUTE 0 // Boot button #define LED_D9 23 #define LIGHT0 15 #define LIGHT1 4 @@ -90,28 +89,26 @@ #endif - -#ifdef GPAD_VERSION1 //The Version 1 PCB. -//#define SS 7 // nCS aka /SS Input on GPAD Version 1 PCB. +#ifdef GPAD_VERSION1 // The Version 1 PCB. +// #define SS 7 // nCS aka /SS Input on GPAD Version 1 PCB. #if defined(HMWK) // const int LED_D9 = 23; // Mute1 LED on PMD -#define LED_PIN 23 // for GPAD LIGHT0 -#define BUTTON_PIN 2 //GPAD Button to GND, 10K Resistor to +5V. -#else // compile for an UNO, for example... -#define LED_PIN PD3 // for GPAD LIGHT0 -#define BUTTON_PIN PD2 //GPAD Button to GND, 10K Resistor to +5V. +#define LED_PIN 23 // for GPAD LIGHT0 +#define BUTTON_PIN 2 // GPAD Button to GND, 10K Resistor to +5V. +#else // compile for an UNO, for example... +#define LED_PIN PD3 // for GPAD LIGHT0 +#define BUTTON_PIN PD2 // GPAD Button to GND, 10K Resistor to +5V. #endif -#else //The proof of concept wiring. +#else // The proof of concept wiring. #define LED_PIN 7 -#define BUTTON_PIN 2 //Button to GND, 10K Resistor to +5V. +#define BUTTON_PIN 2 // Button to GND, 10K Resistor to +5V. #endif - -// Define TX and RX pins for UART1 +// Define TX and RX pins for UART1 // For PCB and for Mocking Krake Maryville -//See also Issue# 94 +// See also Issue# 94 #define TXD1 2 #define RXD1 15 #define UART1_BAUD_RATE 115200 @@ -142,6 +139,5 @@ void interpretBuffer(char *buf, int rlen, Stream *serialport, PubSubClient *clie void GPAD_HAL_setup(Stream *serialport); void GPAD_HAL_loop(); - extern LiquidCrystal_I2C lcd; #endif diff --git a/Firmware/GPAD_API/src/GPAD_menu.cpp b/Firmware/GPAD_API/src/GPAD_menu.cpp new file mode 100644 index 00000000..79728d58 --- /dev/null +++ b/Firmware/GPAD_API/src/GPAD_menu.cpp @@ -0,0 +1,129 @@ +#include +#include +#include +#include +#include +#include "GPAD_HAL.h" +#include "RickmanLiquidCrystal_I2C.h" +#include "DFPlayer.h" + +using namespace Menu; + +extern bool running_menu; +extern bool menu_just_exited; + +#define LEDPIN 12 +#define MAX_DEPTH 1 + +// This needs to be cleaned up; the PubSublcient and WiFi stuff needs to put into a +// a module that is not in GPAD_API.ino +extern PubSubClient client; +extern char publish_Ack_Topic[17]; + +result action1(eventMask e) +{ + if (e == eventMask::enterEvent) + { + Serial.println(F("Yes, I will take that action #1 !")); + } + char onLineMsg[32] = "Acknowledging!"; + client.publish(publish_Ack_Topic, onLineMsg); + Serial.print("Messgage sent to topic: "); + Serial.println(publish_Ack_Topic); + return proceed; +} +result action2(eventMask e) +{ + if (e == eventMask::enterEvent) + { + Serial.println(F("Yes, I will take that action #2 !")); + } + return proceed; +} +result action3(eventMask e) +{ + if (e == eventMask::enterEvent) + { + Serial.println(F("Yes, I will take that action #3 !")); + } + return proceed; +} +result action4(eventMask e) +{ + if (e == eventMask::enterEvent) + { + Serial.println(F("Yes, I will take that action #3 !")); + } + Serial.print(F("volume value: ")); + Serial.println(volumeDFPlayer); + setVolume(volumeDFPlayer); + return proceed; +} +result action5(eventMask e) +{ + Serial.println("exiting menu"); + running_menu = false; + menu_just_exited = true; + Menu::doExit(); + return proceed; +} + +MENU(mainMenu, "Krake Menu", Menu::doNothing, Menu::noEvent, Menu::wrapStyle, OP("Acknowledge", action1, anyEvent), OP("Dismiss", action2, anyEvent), OP("Shelve", action3, anyEvent), FIELD(volumeDFPlayer, "Volume", "%", 0, 30, 10, 1, action4, anyEvent, wrapStyle), OP("Exit Menu", action5, enterEvent)); + +RotaryEventIn reIn( + RotaryEventIn::EventType::BUTTON_CLICKED | // select + RotaryEventIn::EventType::BUTTON_DOUBLE_CLICKED | // back + RotaryEventIn::EventType::BUTTON_LONG_PRESSED | // also back + RotaryEventIn::EventType::ROTARY_CCW | // up + RotaryEventIn::EventType::ROTARY_CW // down +); // register capabilities, see AndroidMenu MenuIO/RotaryEventIn.h file +MENU_INPUTS(in, &reIn); + +// serialIn serial(Serial); +// MENU_INPUTS(in,&serial); + +MENU_OUTPUTS(out, MAX_DEPTH + // ,SERIAL_OUT(Serial) + , + LCD_OUT(lcd, {0, 0, 20, 4}), NONE // must have 2 items at least +); + +NAVROOT(nav, mainMenu, MAX_DEPTH, in, out); + +void registerRotationEvent(bool CW) +{ + Serial.print("CW: "); + Serial.println(CW); + // Note: Rob believes it is more "natural" for clockwise to mean "up". + // Apparently, whoever wrote the "MENU_INPUTS" believes the opposite, + // so I am changing this hear to reverse the sense. + reIn.registerEvent(CW ? RotaryEventIn::EventType::ROTARY_CCW + : RotaryEventIn::EventType::ROTARY_CW); +} + +void registerRotaryEncoderPress() +{ + reIn.registerEvent(RotaryEventIn::EventType::BUTTON_CLICKED); +} + +void setup_GPAD_menu() +{ +} + +void poll_GPAD_menu() +{ + nav.poll(); +} + +void navigate_to_n_and_execute(int n) +{ + Serial.println("moving to zero and executing!"); + nav.doNav(navCmd(idxCmd, n)); // hilite second option + // nav.doNav(navCmd(enterCmd)); //execute option +} + +void reset_menu_navigation() +{ + running_menu = true; + nav.reset(); +} diff --git a/Firmware/GPAD_API/GPAD_menu.h b/Firmware/GPAD_API/src/GPAD_menu.h similarity index 100% rename from Firmware/GPAD_API/GPAD_menu.h rename to Firmware/GPAD_API/src/GPAD_menu.h diff --git a/Firmware/GPAD_API/InterruptRotator.cpp b/Firmware/GPAD_API/src/InterruptRotator.cpp similarity index 100% rename from Firmware/GPAD_API/InterruptRotator.cpp rename to Firmware/GPAD_API/src/InterruptRotator.cpp diff --git a/Firmware/GPAD_API/InterruptRotator.h b/Firmware/GPAD_API/src/InterruptRotator.h similarity index 100% rename from Firmware/GPAD_API/InterruptRotator.h rename to Firmware/GPAD_API/src/InterruptRotator.h diff --git a/Firmware/GPAD_API/README.md b/Firmware/GPAD_API/src/README.md similarity index 100% rename from Firmware/GPAD_API/README.md rename to Firmware/GPAD_API/src/README.md diff --git a/Firmware/GPAD_API/RickmanLiquidCrystal_I2C.h b/Firmware/GPAD_API/src/RickmanLiquidCrystal_I2C.h similarity index 100% rename from Firmware/GPAD_API/RickmanLiquidCrystal_I2C.h rename to Firmware/GPAD_API/src/RickmanLiquidCrystal_I2C.h diff --git a/Firmware/GPAD_API/WiFiManagerOTA.cpp b/Firmware/GPAD_API/src/WiFiManagerOTA.cpp similarity index 100% rename from Firmware/GPAD_API/WiFiManagerOTA.cpp rename to Firmware/GPAD_API/src/WiFiManagerOTA.cpp diff --git a/Firmware/GPAD_API/WiFiManagerOTA.h b/Firmware/GPAD_API/src/WiFiManagerOTA.h similarity index 100% rename from Firmware/GPAD_API/WiFiManagerOTA.h rename to Firmware/GPAD_API/src/WiFiManagerOTA.h diff --git a/Firmware/GPAD_API/Wink.cpp b/Firmware/GPAD_API/src/Wink.cpp similarity index 100% rename from Firmware/GPAD_API/Wink.cpp rename to Firmware/GPAD_API/src/Wink.cpp diff --git a/Firmware/GPAD_API/Wink.h b/Firmware/GPAD_API/src/Wink.h similarity index 100% rename from Firmware/GPAD_API/Wink.h rename to Firmware/GPAD_API/src/Wink.h diff --git a/Firmware/GPAD_API/alarm_api.cpp b/Firmware/GPAD_API/src/alarm_api.cpp similarity index 100% rename from Firmware/GPAD_API/alarm_api.cpp rename to Firmware/GPAD_API/src/alarm_api.cpp diff --git a/Firmware/GPAD_API/alarm_api.h b/Firmware/GPAD_API/src/alarm_api.h similarity index 100% rename from Firmware/GPAD_API/alarm_api.h rename to Firmware/GPAD_API/src/alarm_api.h diff --git a/Firmware/GPAD_API/data/favicon.png b/Firmware/GPAD_API/src/data/favicon.png similarity index 100% rename from Firmware/GPAD_API/data/favicon.png rename to Firmware/GPAD_API/src/data/favicon.png diff --git a/Firmware/GPAD_API/data/index.html b/Firmware/GPAD_API/src/data/index.html similarity index 100% rename from Firmware/GPAD_API/data/index.html rename to Firmware/GPAD_API/src/data/index.html diff --git a/Firmware/GPAD_API/data/style.css b/Firmware/GPAD_API/src/data/style.css similarity index 100% rename from Firmware/GPAD_API/data/style.css rename to Firmware/GPAD_API/src/data/style.css diff --git a/Firmware/GPAD_API/gpad_serial.cpp b/Firmware/GPAD_API/src/gpad_serial.cpp similarity index 100% rename from Firmware/GPAD_API/gpad_serial.cpp rename to Firmware/GPAD_API/src/gpad_serial.cpp diff --git a/Firmware/GPAD_API/gpad_serial.h b/Firmware/GPAD_API/src/gpad_serial.h similarity index 100% rename from Firmware/GPAD_API/gpad_serial.h rename to Firmware/GPAD_API/src/gpad_serial.h diff --git a/Firmware/GPAD_API/gpad_utility.cpp b/Firmware/GPAD_API/src/gpad_utility.cpp similarity index 100% rename from Firmware/GPAD_API/gpad_utility.cpp rename to Firmware/GPAD_API/src/gpad_utility.cpp diff --git a/Firmware/GPAD_API/gpad_utility.h b/Firmware/GPAD_API/src/gpad_utility.h similarity index 100% rename from Firmware/GPAD_API/gpad_utility.h rename to Firmware/GPAD_API/src/gpad_utility.h diff --git a/Firmware/GPAD_API/test/README b/Firmware/GPAD_API/test/README new file mode 100644 index 00000000..9b1e87bc --- /dev/null +++ b/Firmware/GPAD_API/test/README @@ -0,0 +1,11 @@ + +This directory is intended for PlatformIO Test Runner and project tests. + +Unit Testing is a software testing method by which individual units of +source code, sets of one or more MCU program modules together with associated +control data, usage procedures, and operating procedures, are tested to +determine whether they are fit for use. Unit testing finds problems early +in the development cycle. + +More information about PlatformIO Unit Testing: +- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html From 424d58673340588d3bcb120beb3620ab1482c6b1 Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Mon, 27 Oct 2025 22:08:02 -0400 Subject: [PATCH 02/21] #273: Adding README for build/install instructions --- Firmware/GPAD_API/README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 Firmware/GPAD_API/README.md diff --git a/Firmware/GPAD_API/README.md b/Firmware/GPAD_API/README.md new file mode 100644 index 00000000..07a0153e --- /dev/null +++ b/Firmware/GPAD_API/README.md @@ -0,0 +1,14 @@ +# Building + +## PlatformIO IDE (Visual Studio Code Extension) +1. Install the Visual Studio Code (VS Code) text editor + - [Website](https://code.visualstudio.com/) +2. Install the [PlatformIO](https://marketplace.visualstudio.com/items?itemName=platformio.platformio-ide) VS Code extension + - The provided link has instructions on how install the extension in VS Code +3. The PlatformIO project needs to be opened + - Click the PlatformIO logo/extension on the left tool bar + - Under the `QUICK ACCESS > PIO Home` section, selection `Projects & Configuration` + - At the top, select `Add Existing` and select this directory +4. To compile, select the PlatformIO logo/extension on the left again if it is not still selected + - Under `esp32dev > General` select `Build` and the firmware image will be built + - There are additional options for uploading the firmware to the device and monitoring \ No newline at end of file From 6afcfd26053a60445eb36c78286158e05f26b7a2 Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Mon, 3 Nov 2025 13:50:11 -0500 Subject: [PATCH 03/21] #273: Reorder dependencies in platformio.ini - Moved WiFiManager and ElegantOTA libraries to the bottom of the list - Clean builds failed during first compilation due to libraries depending on other libraries not build yet --- Firmware/GPAD_API/platformio.ini | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Firmware/GPAD_API/platformio.ini b/Firmware/GPAD_API/platformio.ini index 9050cb5b..0c553ad2 100644 --- a/Firmware/GPAD_API/platformio.ini +++ b/Firmware/GPAD_API/platformio.ini @@ -10,18 +10,18 @@ [env:esp32dev] build_flags = - -DELEGANTOTA_USE_ASYNC_WEBSERVER=1 + -DELEGANTOTA_USE_ASYNC_WEBSERVER=1 platform = espressif32 board = esp32dev framework = arduino lib_extra_dirs = ~/Documents/Arduino/libraries lib_deps = - mathertel/RotaryEncoder@^1.5.3 - knolleary/PubSubClient@^2.8 - neu-rah/ArduinoMenu library@^4.21.5 - cygig/DailyStruggleButton@^0.5.1 - neu-rah/streamFlow@0.0.0-alpha+sha.bf16ce8926 - tzapu/WiFiManager@^2.0.17 - ayushsharma82/ElegantOTA@^3.1.7 - marcoschwartz/LiquidCrystal_I2C@^1.1.4 - dfrobot/DFRobotDFPlayerMini@^1.0.6 + mathertel/RotaryEncoder@^1.5.3 + knolleary/PubSubClient@^2.8 + neu-rah/ArduinoMenu library@^4.21.5 + cygig/DailyStruggleButton@^0.5.1 + neu-rah/streamFlow@0.0.0-alpha+sha.bf16ce8926 + marcoschwartz/LiquidCrystal_I2C@^1.1.4 + dfrobot/DFRobotDFPlayerMini@^1.0.6 + tzapu/WiFiManager@^2.0.17 + ayushsharma82/ElegantOTA@^3.1.7 From 80c06fa6cbe2217e77e3f8cb2f346ef988997dc7 Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Tue, 11 Nov 2025 19:02:08 -0500 Subject: [PATCH 04/21] #273: Setting correct baud rate - The baud rate with PlatformIO defaults to 9800 - The correct baud rate for the serial connection with the ESP32-WROOM is 115200 --- Firmware/GPAD_API/platformio.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/Firmware/GPAD_API/platformio.ini b/Firmware/GPAD_API/platformio.ini index 0c553ad2..5221b6e0 100644 --- a/Firmware/GPAD_API/platformio.ini +++ b/Firmware/GPAD_API/platformio.ini @@ -13,6 +13,7 @@ build_flags = -DELEGANTOTA_USE_ASYNC_WEBSERVER=1 platform = espressif32 board = esp32dev +monitor_speed = 115200 framework = arduino lib_extra_dirs = ~/Documents/Arduino/libraries lib_deps = From 620b0d10aa37e8df46d756755c45569117120ac0 Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Tue, 11 Nov 2025 22:06:28 -0500 Subject: [PATCH 05/21] #273: Defines are provided via a build script - The defines in `gpad_utility.h` are still defined in the file for completeness - The values are empty since the values are now fed in via a pre-build script - The benefit of this is that to change the values of the defines does not require modifying a source file - The values, like the firmware version and product name, can now be provided programmatically - Like pulling a version from git tag - A static config file with the values --- Firmware/GPAD_API/platformio.ini | 2 ++ Firmware/GPAD_API/pre_extra_script.py | 14 ++++++++++++++ Firmware/GPAD_API/src/gpad_utility.h | 24 ++++++++++++++++++------ 3 files changed, 34 insertions(+), 6 deletions(-) create mode 100644 Firmware/GPAD_API/pre_extra_script.py diff --git a/Firmware/GPAD_API/platformio.ini b/Firmware/GPAD_API/platformio.ini index 5221b6e0..fb5aac26 100644 --- a/Firmware/GPAD_API/platformio.ini +++ b/Firmware/GPAD_API/platformio.ini @@ -9,6 +9,8 @@ ; https://docs.platformio.org/page/projectconf.html [env:esp32dev] +extra_scripts = + pre:pre_extra_script.py build_flags = -DELEGANTOTA_USE_ASYNC_WEBSERVER=1 platform = espressif32 diff --git a/Firmware/GPAD_API/pre_extra_script.py b/Firmware/GPAD_API/pre_extra_script.py new file mode 100644 index 00000000..023a37ef --- /dev/null +++ b/Firmware/GPAD_API/pre_extra_script.py @@ -0,0 +1,14 @@ +Import("env") + +cpp_defines = [ + ("COMPANY_NAME", "PubInv "), # For the Broker ID for MQTT + ("PROG_NAME", "GPAD_API "), # This program + ("FIRMWARE_VERSION", "0.45 "), # Initial Menu implementation + ("MODEL_NAME", "KRAKE_"), + ("LICENSE", "GNU Affero General Public License, version 3 "), + ("ORIGIN", "US"), +] + +stringify_lambda = lambda macro: (macro[0], env.StringifyMacro(macro[1])) + +env.Append(CPPDEFINES=map(stringify_lambda, cpp_defines)) diff --git a/Firmware/GPAD_API/src/gpad_utility.h b/Firmware/GPAD_API/src/gpad_utility.h index 328d2ff8..0070ac6b 100644 --- a/Firmware/GPAD_API/src/gpad_utility.h +++ b/Firmware/GPAD_API/src/gpad_utility.h @@ -21,13 +21,25 @@ #ifndef GPAD_UTILITY #define GPAD_UTILITY 1 #include -#define COMPANY_NAME "PubInv " // For the Broker ID for MQTT -#define PROG_NAME "GPAD_API " // This program -#define FIRMWARE_VERSION "0.44 " // Initial Menu implementation +#ifndef COMPANY_NAME + #define COMPANY_NAME "" +#endif +#ifndef PROG_NAME + #define PROG_NAME "" +#endif +#ifndef FIRMWARE_VERSION + #define FIRMWARE_VERSION "" +#endif //#define HARDWARE_VERSION "V0.0.1 " -#define MODEL_NAME "KRAKE_" -#define LICENSE "GNU Affero General Public License, version 3 " -#define ORIGIN "US" +#ifndef MODEL_NAME + #define MODEL_NAME "" +#endif +#ifndef LICENSE + #define LICENSE "" +#endif +#ifndef ORIGIN + #define ORIGIN "" +#endif #define DEVICE_UNDER_TEST "Krake: DFPlayer" //This is GPAD code, but if it is used in testing... // THIS IS FOR DEBUGGING From 9e4291a8a3783def422a1e098880ae0d26f530a5 Mon Sep 17 00:00:00 2001 From: "Robert L. Read" Date: Wed, 12 Nov 2025 22:30:47 -0600 Subject: [PATCH 06/21] rob improves documentation and adds a makefile --- Firmware/GPAD_API/README.md | 26 +++++++++++++++++++++++++- Firmware/GPAD_API/makefile | 23 +++++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 Firmware/GPAD_API/makefile diff --git a/Firmware/GPAD_API/README.md b/Firmware/GPAD_API/README.md index 07a0153e..ee6652a4 100644 --- a/Firmware/GPAD_API/README.md +++ b/Firmware/GPAD_API/README.md @@ -11,4 +11,28 @@ - At the top, select `Add Existing` and select this directory 4. To compile, select the PlatformIO logo/extension on the left again if it is not still selected - Under `esp32dev > General` select `Build` and the firmware image will be built - - There are additional options for uploading the firmware to the device and monitoring \ No newline at end of file + - There are additional options for uploading the firmware to the device and monitoring + +## PlatformIO from Command Line + + Some users prefer not to use VSCode (those who prefer Emacs, Vim, subtext, etc.) + + In the this directory, there is a "make" file. If you have make installed, you can run "make". There are two targets: + + 1. run --- this does a compile and upload, and begins running a "monitor", which prints the output of the serial monitor and allows commands to be typed in, just as they are typically done in the Arduino IDE. + 2. monitor --- this does a reset and runs the monitor without doing a fully reset. + +These commands are implemented on the command line as: + +``` + make run + make monitor +``` + + Remember, with our current hardware, to prepare the Krake to have firmware uploaded, you need to perform these actions: + + 1. Connect Krake to power and to the computer + 2. Press and hold the BOOT button. + 3. While still holding BOOT, press and release the RESET button once. + 4. Release the BOOT button. + 5. The chip is now in boot mode. You can run your flasher and the port should respond. \ No newline at end of file diff --git a/Firmware/GPAD_API/makefile b/Firmware/GPAD_API/makefile new file mode 100644 index 00000000..cfa6a6f7 --- /dev/null +++ b/Firmware/GPAD_API/makefile @@ -0,0 +1,23 @@ +# Copyright 2025, Robert Read +# +# This program includes free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# See the GNU Affero General Public License for more details. +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# + + +run: + pio run -t upload \ + && pio device monitor -b 115200 + +monitor: + pio device monitor -b 115200 From 4b759bb9940ef066aedb4a07037ce838f6f3d8c6 Mon Sep 17 00:00:00 2001 From: "Robert L. Read" Date: Sat, 15 Nov 2025 20:37:55 -0600 Subject: [PATCH 07/21] restoring firmware version, and removing the refrence to Arduino Libaries --- Firmware/GPAD_API/platformio.ini | 27 +++++++++++++-------------- Firmware/GPAD_API/src/gpad_utility.h | 12 ++++++------ 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/Firmware/GPAD_API/platformio.ini b/Firmware/GPAD_API/platformio.ini index fb5aac26..1dbaf443 100644 --- a/Firmware/GPAD_API/platformio.ini +++ b/Firmware/GPAD_API/platformio.ini @@ -9,22 +9,21 @@ ; https://docs.platformio.org/page/projectconf.html [env:esp32dev] -extra_scripts = - pre:pre_extra_script.py -build_flags = - -DELEGANTOTA_USE_ASYNC_WEBSERVER=1 +extra_scripts = + pre:pre_extra_script.py +build_flags = + -DELEGANTOTA_USE_ASYNC_WEBSERVER=1 platform = espressif32 board = esp32dev monitor_speed = 115200 framework = arduino -lib_extra_dirs = ~/Documents/Arduino/libraries lib_deps = - mathertel/RotaryEncoder@^1.5.3 - knolleary/PubSubClient@^2.8 - neu-rah/ArduinoMenu library@^4.21.5 - cygig/DailyStruggleButton@^0.5.1 - neu-rah/streamFlow@0.0.0-alpha+sha.bf16ce8926 - marcoschwartz/LiquidCrystal_I2C@^1.1.4 - dfrobot/DFRobotDFPlayerMini@^1.0.6 - tzapu/WiFiManager@^2.0.17 - ayushsharma82/ElegantOTA@^3.1.7 + mathertel/RotaryEncoder@^1.5.3 + knolleary/PubSubClient@^2.8 + neu-rah/ArduinoMenu library@^4.21.5 + cygig/DailyStruggleButton@^0.5.1 + neu-rah/streamFlow@0.0.0-alpha+sha.bf16ce8926 + dfrobot/DFRobotDFPlayerMini@^1.0.6 + tzapu/WiFiManager@^2.0.17 + ayushsharma82/ElegantOTA@^3.1.7 + marcoschwartz/LiquidCrystal_I2C@^1.1.4 diff --git a/Firmware/GPAD_API/src/gpad_utility.h b/Firmware/GPAD_API/src/gpad_utility.h index 0070ac6b..db50ff0d 100644 --- a/Firmware/GPAD_API/src/gpad_utility.h +++ b/Firmware/GPAD_API/src/gpad_utility.h @@ -22,23 +22,23 @@ #define GPAD_UTILITY 1 #include #ifndef COMPANY_NAME - #define COMPANY_NAME "" + #define COMPANY_NAME "PubInv " #endif #ifndef PROG_NAME - #define PROG_NAME "" + #define PROG_NAME "GPAD_API " #endif #ifndef FIRMWARE_VERSION - #define FIRMWARE_VERSION "" + #define FIRMWARE_VERSION "0.46 " #endif //#define HARDWARE_VERSION "V0.0.1 " #ifndef MODEL_NAME - #define MODEL_NAME "" + #define MODEL_NAME "KRAKE_" #endif #ifndef LICENSE - #define LICENSE "" + #define LICENSE "GNU Affero General Public License, version 3 " #endif #ifndef ORIGIN - #define ORIGIN "" + #define ORIGIN "US" #endif #define DEVICE_UNDER_TEST "Krake: DFPlayer" //This is GPAD code, but if it is used in testing... From 6dcc419a2cfce3d37e54d4cc4f7f0624ace15b84 Mon Sep 17 00:00:00 2001 From: "Robert L. Read" Date: Wed, 12 Nov 2025 22:46:59 -0600 Subject: [PATCH 08/21] Update README.md --- Firmware/GPAD_API/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Firmware/GPAD_API/README.md b/Firmware/GPAD_API/README.md index ee6652a4..fc8ebcf4 100644 --- a/Firmware/GPAD_API/README.md +++ b/Firmware/GPAD_API/README.md @@ -15,9 +15,9 @@ ## PlatformIO from Command Line - Some users prefer not to use VSCode (those who prefer Emacs, Vim, subtext, etc.) +Some users prefer not to use VSCode (those who prefer Emacs, Vim, subtext, etc.) - In the this directory, there is a "make" file. If you have make installed, you can run "make". There are two targets: +In the this directory, there is a "make" file. If you have make installed, you can run "make". There are two targets: 1. run --- this does a compile and upload, and begins running a "monitor", which prints the output of the serial monitor and allows commands to be typed in, just as they are typically done in the Arduino IDE. 2. monitor --- this does a reset and runs the monitor without doing a fully reset. @@ -29,10 +29,10 @@ These commands are implemented on the command line as: make monitor ``` - Remember, with our current hardware, to prepare the Krake to have firmware uploaded, you need to perform these actions: +Remember, with our current hardware, to prepare the Krake to have firmware uploaded, you need to perform these actions: 1. Connect Krake to power and to the computer 2. Press and hold the BOOT button. 3. While still holding BOOT, press and release the RESET button once. 4. Release the BOOT button. - 5. The chip is now in boot mode. You can run your flasher and the port should respond. \ No newline at end of file + 5. The chip is now in boot mode. You can run your flasher and the port should respond. From 86c78b9c8722763d17c65c1854d2c021d7083ca5 Mon Sep 17 00:00:00 2001 From: "Robert L. Read" Date: Wed, 12 Nov 2025 22:47:29 -0600 Subject: [PATCH 09/21] Update README.md --- Firmware/GPAD_API/README.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Firmware/GPAD_API/README.md b/Firmware/GPAD_API/README.md index fc8ebcf4..4c42ba52 100644 --- a/Firmware/GPAD_API/README.md +++ b/Firmware/GPAD_API/README.md @@ -30,9 +30,8 @@ These commands are implemented on the command line as: ``` Remember, with our current hardware, to prepare the Krake to have firmware uploaded, you need to perform these actions: - - 1. Connect Krake to power and to the computer - 2. Press and hold the BOOT button. - 3. While still holding BOOT, press and release the RESET button once. - 4. Release the BOOT button. - 5. The chip is now in boot mode. You can run your flasher and the port should respond. +1. Connect Krake to power and to the computer +2. Press and hold the BOOT button. +3. While still holding BOOT, press and release the RESET button once. +4. Release the BOOT button. +5. The chip is now in boot mode. You can run your flasher and the port should respond. From e4742091dd96aa0bc75ad158ade3a0deee39c29c Mon Sep 17 00:00:00 2001 From: "Robert L. Read" Date: Sat, 15 Nov 2025 21:08:55 -0600 Subject: [PATCH 10/21] Bump version to 46 and back-out my changes to gpad_utility.h --- Firmware/GPAD_API/pre_extra_script.py | 2 +- Firmware/GPAD_API/src/GPAD_API.ino | 1 - Firmware/GPAD_API/src/gpad_utility.h | 10 +++++----- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/Firmware/GPAD_API/pre_extra_script.py b/Firmware/GPAD_API/pre_extra_script.py index 023a37ef..e83baff2 100644 --- a/Firmware/GPAD_API/pre_extra_script.py +++ b/Firmware/GPAD_API/pre_extra_script.py @@ -3,7 +3,7 @@ cpp_defines = [ ("COMPANY_NAME", "PubInv "), # For the Broker ID for MQTT ("PROG_NAME", "GPAD_API "), # This program - ("FIRMWARE_VERSION", "0.45 "), # Initial Menu implementation + ("FIRMWARE_VERSION", "0.46 "), # Initial Menu implementation ("MODEL_NAME", "KRAKE_"), ("LICENSE", "GNU Affero General Public License, version 3 "), ("ORIGIN", "US"), diff --git a/Firmware/GPAD_API/src/GPAD_API.ino b/Firmware/GPAD_API/src/GPAD_API.ino index 7b434dc6..6f8b7e48 100644 --- a/Firmware/GPAD_API/src/GPAD_API.ino +++ b/Firmware/GPAD_API/src/GPAD_API.ino @@ -526,7 +526,6 @@ bool menu_just_exited = false; void loop() { - bool is_WIFIconnected = false; unsigned long ms = millis(); if (ms - time_since_LOW_FREQ_ms > LOW_FREQ_DEBUG_MS) diff --git a/Firmware/GPAD_API/src/gpad_utility.h b/Firmware/GPAD_API/src/gpad_utility.h index db50ff0d..bd4e68fc 100644 --- a/Firmware/GPAD_API/src/gpad_utility.h +++ b/Firmware/GPAD_API/src/gpad_utility.h @@ -22,23 +22,23 @@ #define GPAD_UTILITY 1 #include #ifndef COMPANY_NAME - #define COMPANY_NAME "PubInv " + #define COMPANY_NAME "" #endif #ifndef PROG_NAME - #define PROG_NAME "GPAD_API " + #define PROG_NAME "" #endif #ifndef FIRMWARE_VERSION - #define FIRMWARE_VERSION "0.46 " + #define FIRMWARE_VERSION "" #endif //#define HARDWARE_VERSION "V0.0.1 " #ifndef MODEL_NAME - #define MODEL_NAME "KRAKE_" + #define MODEL_NAME "" #endif #ifndef LICENSE #define LICENSE "GNU Affero General Public License, version 3 " #endif #ifndef ORIGIN - #define ORIGIN "US" + #define ORIGIN "" #endif #define DEVICE_UNDER_TEST "Krake: DFPlayer" //This is GPAD code, but if it is used in testing... From 750d85822c0b6b82ee0d9d4b9cfed626169a3f21 Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Sat, 15 Nov 2025 21:21:45 -0500 Subject: [PATCH 11/21] (#273): Corrected data directory for LittleFS content --- Firmware/GPAD_API/{src => }/data/favicon.png | Bin Firmware/GPAD_API/{src => }/data/index.html | 0 Firmware/GPAD_API/{src => }/data/style.css | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename Firmware/GPAD_API/{src => }/data/favicon.png (100%) rename Firmware/GPAD_API/{src => }/data/index.html (100%) rename Firmware/GPAD_API/{src => }/data/style.css (100%) diff --git a/Firmware/GPAD_API/src/data/favicon.png b/Firmware/GPAD_API/data/favicon.png similarity index 100% rename from Firmware/GPAD_API/src/data/favicon.png rename to Firmware/GPAD_API/data/favicon.png diff --git a/Firmware/GPAD_API/src/data/index.html b/Firmware/GPAD_API/data/index.html similarity index 100% rename from Firmware/GPAD_API/src/data/index.html rename to Firmware/GPAD_API/data/index.html diff --git a/Firmware/GPAD_API/src/data/style.css b/Firmware/GPAD_API/data/style.css similarity index 100% rename from Firmware/GPAD_API/src/data/style.css rename to Firmware/GPAD_API/data/style.css From 830df77f4e483667eb4ffcbc5826012a2b70bf43 Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Sun, 16 Nov 2025 15:03:46 -0500 Subject: [PATCH 12/21] (#273): Auto formatting/styling --- Firmware/GPAD_API/platformio.ini | 1 + Firmware/GPAD_API/src/DFPlayer.cpp | 336 +++++---- Firmware/GPAD_API/src/DFPlayer.h | 2 +- Firmware/GPAD_API/src/GPAD_API.ino | 2 +- Firmware/GPAD_API/src/GPAD_HAL.cpp | 713 ++++++++++-------- Firmware/GPAD_API/src/GPAD_menu.h | 5 +- Firmware/GPAD_API/src/InterruptRotator.cpp | 36 +- Firmware/GPAD_API/src/InterruptRotator.h | 11 +- .../GPAD_API/src/RickmanLiquidCrystal_I2C.h | 93 +-- Firmware/GPAD_API/src/WiFiManagerOTA.cpp | 62 +- Firmware/GPAD_API/src/WiFiManagerOTA.h | 10 +- Firmware/GPAD_API/src/Wink.cpp | 32 +- Firmware/GPAD_API/src/Wink.h | 6 +- Firmware/GPAD_API/src/alarm_api.cpp | 18 +- Firmware/GPAD_API/src/alarm_api.h | 18 +- Firmware/GPAD_API/src/gpad_serial.cpp | 16 +- Firmware/GPAD_API/src/gpad_serial.h | 6 +- Firmware/GPAD_API/src/gpad_utility.cpp | 17 +- Firmware/GPAD_API/src/gpad_utility.h | 16 +- 19 files changed, 761 insertions(+), 639 deletions(-) diff --git a/Firmware/GPAD_API/platformio.ini b/Firmware/GPAD_API/platformio.ini index 1dbaf443..186aa19f 100644 --- a/Firmware/GPAD_API/platformio.ini +++ b/Firmware/GPAD_API/platformio.ini @@ -15,6 +15,7 @@ build_flags = -DELEGANTOTA_USE_ASYNC_WEBSERVER=1 platform = espressif32 board = esp32dev +board_build.filesystem = littlefs monitor_speed = 115200 framework = arduino lib_deps = diff --git a/Firmware/GPAD_API/src/DFPlayer.cpp b/Firmware/GPAD_API/src/DFPlayer.cpp index 7b171e32..ba71fbfb 100644 --- a/Firmware/GPAD_API/src/DFPlayer.cpp +++ b/Firmware/GPAD_API/src/DFPlayer.cpp @@ -4,36 +4,35 @@ #include DFRobotDFPlayerMini dfPlayer; -HardwareSerial mySerial1(2); // Use UART2 +HardwareSerial mySerial1(2); // Use UART2 -const int LED_PIN = 13; // Krake -//const int LED_PIN = 2; // ESP32 LED +const int LED_PIN = 13; // Krake +// const int LED_PIN = 2; // ESP32 LED -const int nDFPlayer_BUSY = 4; //not Busy from DFPLayer +const int nDFPlayer_BUSY = 4; // not Busy from DFPLayer bool isDFPlayerDetected = false; -int volumeDFPlayer = 20; // Set volume initial volume. Range is [0 to 30] -int numberFilesDF = 0; // Number of the audio files found. - - +int volumeDFPlayer = 20; // Set volume initial volume. Range is [0 to 30] +int numberFilesDF = 0; // Number of the audio files found. // The serial command system is from: https://www.dfrobot.com/blog-1462.html?srsltid=AfmBOoqm5pHrLswInrTwZ9vcYdxxPC_zH2zXnoro2FyTLEL4L57IW3Sn char command; int pausa = 0; - -void serialSplashDFP() { +void serialSplashDFP() +{ Serial.println("==================================="); Serial.println(DEVICE_UNDER_TEST); Serial.print(PROG_NAME); Serial.println(FIRMWARE_VERSION); Serial.print("Compiled at: "); - Serial.println(F(__DATE__ " " __TIME__)); //compile date that is used for a unique identifier + Serial.println(F(__DATE__ " " __TIME__)); // compile date that is used for a unique identifier Serial.println("==================================="); Serial.println(); } -void menu_opcoes() { +void menu_opcoes() +{ Serial.println(); Serial.println(F("==================================================================================================================================")); Serial.println(F("Commands:")); @@ -44,16 +43,18 @@ void menu_opcoes() { Serial.println(F(" [< or >] forwards or backwards the track")); Serial.println(); Serial.println(F("=================================================================================================================================")); -} //end menu_opcoes() - +} // end menu_opcoes() -void checkSerial(void) { +void checkSerial(void) +{ - //Waits for data entry via serial - while (Serial.available() > 0) { + // Waits for data entry via serial + while (Serial.available() > 0) + { command = Serial.read(); - if ((command >= '1') && (command <= '9')) { + if ((command >= '1') && (command <= '9')) + { Serial.print("Music reproduction"); Serial.println(command); command = command - 48; @@ -61,24 +62,28 @@ void checkSerial(void) { menu_opcoes(); } - //Reproduction - //Stop + // Reproduction + // Stop - if (command == 's') { + if (command == 's') + { dfPlayer.stop(); Serial.println("Music Stopped!"); menu_opcoes(); } - //Pausa/Continua a musica - if (command == 'p') { + // Pausa/Continua a musica + if (command == 'p') + { pausa = !pausa; - if (pausa == 0) { + if (pausa == 0) + { Serial.println("Continue..."); dfPlayer.start(); } - if (pausa == 1) { + if (pausa == 1) + { Serial.println("Music Paused!"); dfPlayer.pause(); } @@ -86,16 +91,17 @@ void checkSerial(void) { menu_opcoes(); } - - //Increases volume - if (command == '+') { + // Increases volume + if (command == '+') + { dfPlayer.volumeUp(); Serial.print("Current volume:"); Serial.println(dfPlayer.readVolume()); menu_opcoes(); } - if (command == '<') { + if (command == '<') + { dfPlayer.previous(); Serial.println("Previous:"); Serial.print("Current track:"); @@ -103,7 +109,8 @@ void checkSerial(void) { menu_opcoes(); } - if (command == '>') { + if (command == '>') + { dfPlayer.next(); Serial.println("next:"); Serial.print("Current track:"); @@ -111,228 +118,248 @@ void checkSerial(void) { menu_opcoes(); } - //Decreases volume - if (command == '-') { + // Decreases volume + if (command == '-') + { dfPlayer.volumeDown(); Serial.print("Current Volume:"); Serial.println(dfPlayer.readVolume()); menu_opcoes(); } } -} // end checkSerial +} // end checkSerial -//Functions -void setupDFPlayer() { -// Debatably, this this should be in the GPAD_HAL, not here....but -// it is modular to place it here. +// Functions +void setupDFPlayer() +{ + // Debatably, this this should be in the GPAD_HAL, not here....but + // it is modular to place it here. pinMode(nDFPlayer_BUSY, INPUT_PULLUP); - // Setup UART for DFPlayer Serial.println("UART2 Begin"); mySerial1.begin(BAUD_DFPLAYER, SERIAL_8N1, RXD2, TXD2); - while (!mySerial1) { + while (!mySerial1) + { Serial.println("UART2 inot initilaized."); delay(100); - ; // wait for DFPlayer serial port to connect. + ; // wait for DFPlayer serial port to connect. } Serial.println("Begin DFPlayer: isACK true, doReset false."); - if (!dfPlayer.begin(mySerial1, true, false)) { + if (!dfPlayer.begin(mySerial1, true, false)) + { Serial.println("DFPlayer Mini not detected or not working."); Serial.println("Check for missing SD Card."); isDFPlayerDetected = false; - } else { + } + else + { isDFPlayerDetected = true; Serial.println("DFPlayer Mini detected!"); } - dfPlayer.volume(volumeDFPlayer); // Set initial volume - dfPlayer.setTimeOut(500); // Set serial communictaion time out 500ms + dfPlayer.volume(volumeDFPlayer); // Set initial volume + dfPlayer.setTimeOut(500); // Set serial communictaion time out 500ms // delay(100); - dfPlayer.start(); //Todo, ?? necessary for DFPlayer processing + dfPlayer.start(); // Todo, ?? necessary for DFPlayer processing delay(1000); -// dfPlayer.play(11); //DFPlayer Splash + // dfPlayer.play(11); //DFPlayer Splash dfPlayer.play(9); delay(100); dfPlayer.stop(); delay(1000); dfPlayer.previous(); delay(1500); - dfPlayer.play(); //DFPlayer Splash + dfPlayer.play(); // DFPlayer Splash displayDFPlayerStats(); -} //setupDFPLayer +} // setupDFPLayer - -void setVolume(int zeroToThirty) { +void setVolume(int zeroToThirty) +{ dfPlayer.volume(zeroToThirty); } - -void displayDFPlayerStats() { +void displayDFPlayerStats() +{ Serial.print("================="); Serial.print("dfPlayer State: "); - Serial.println(dfPlayer.readState()); //read mp3 state + Serial.println(dfPlayer.readState()); // read mp3 state Serial.print("dfPlayer Volume: "); - Serial.println(dfPlayer.readVolume()); //read current volume + Serial.println(dfPlayer.readVolume()); // read current volume Serial.print("dfPlayer EQ: "); - Serial.println(dfPlayer.readEQ()); //read EQ setting + Serial.println(dfPlayer.readEQ()); // read EQ setting Serial.print("SD Card FileCounts: "); - Serial.println(dfPlayer.readFileCounts()); //read all file counts in SD card + Serial.println(dfPlayer.readFileCounts()); // read all file counts in SD card Serial.print("Current File Number: "); numberFilesDF = dfPlayer.readCurrentFileNumber(); - Serial.println(numberFilesDF); //Display the read current play file number + Serial.println(numberFilesDF); // Display the read current play file number Serial.print("File Counts In Folder: "); - Serial.println(dfPlayer.readFileCountsInFolder(3)); //read file counts in folder SD:/03 + Serial.println(dfPlayer.readFileCountsInFolder(3)); // read file counts in folder SD:/03 // dfPlayer.EQ(0); // Normal equalization //Causes program lock up Serial.print("================="); } -void printDetail(uint8_t type, int value) { - switch (type) { - case TimeOut: - Serial.println(F("Time Out!")); - break; - case WrongStack: - Serial.println(F("Stack Wrong!")); +void printDetail(uint8_t type, int value) +{ + switch (type) + { + case TimeOut: + Serial.println(F("Time Out!")); + break; + case WrongStack: + Serial.println(F("Stack Wrong!")); + break; + case DFPlayerCardInserted: + Serial.println(F("Card Inserted!")); + break; + case DFPlayerCardRemoved: + Serial.println(F("Card Removed!")); + break; + case DFPlayerCardOnline: + Serial.println(F("Card Online!")); + break; + case DFPlayerUSBInserted: + Serial.println("USB Inserted!"); + break; + case DFPlayerUSBRemoved: + Serial.println("USB Removed!"); + break; + case DFPlayerPlayFinished: + Serial.print(F("Number:")); + Serial.print(value); + Serial.println(F(" Play Finished!")); + break; + case DFPlayerError: + Serial.print(F("DFPlayerError:")); + switch (value) + { + case Busy: + Serial.println(F("Card not found")); break; - case DFPlayerCardInserted: - Serial.println(F("Card Inserted!")); + case Sleeping: + Serial.println(F("Sleeping")); break; - case DFPlayerCardRemoved: - Serial.println(F("Card Removed!")); + case SerialWrongStack: + Serial.println(F("Get Wrong Stack")); break; - case DFPlayerCardOnline: - Serial.println(F("Card Online!")); + case CheckSumNotMatch: + Serial.println(F("Check Sum Not Match")); break; - case DFPlayerUSBInserted: - Serial.println("USB Inserted!"); + case FileIndexOut: + Serial.println(F("File Index Out of Bound")); break; - case DFPlayerUSBRemoved: - Serial.println("USB Removed!"); + case FileMismatch: + Serial.println(F("Cannot Find File")); break; - case DFPlayerPlayFinished: - Serial.print(F("Number:")); - Serial.print(value); - Serial.println(F(" Play Finished!")); - break; - case DFPlayerError: - Serial.print(F("DFPlayerError:")); - switch (value) { - case Busy: - Serial.println(F("Card not found")); - break; - case Sleeping: - Serial.println(F("Sleeping")); - break; - case SerialWrongStack: - Serial.println(F("Get Wrong Stack")); - break; - case CheckSumNotMatch: - Serial.println(F("Check Sum Not Match")); - break; - case FileIndexOut: - Serial.println(F("File Index Out of Bound")); - break; - case FileMismatch: - Serial.println(F("Cannot Find File")); - break; - case Advertise: - Serial.println(F("In Advertise")); - break; - default: - break; - } + case Advertise: + Serial.println(F("In Advertise")); break; default: break; + } + break; + default: + break; } -} //end printDetail for DFPlayer +} // end printDetail for DFPlayer - -void dfPlayerUpdate(void) { - unsigned long timePlay = 3000; //Plays 3 seconds of all files. +void dfPlayerUpdate(void) +{ + unsigned long timePlay = 3000; // Plays 3 seconds of all files. static unsigned long timer = millis(); - if (millis() - timer > timePlay) { + if (millis() - timer > timePlay) + { // if (millis() - timer > 10000) { timer = millis(); - dfPlayer.next(); //Play next mp3 every 3 second. + dfPlayer.next(); // Play next mp3 every 3 second. } - if (dfPlayer.available()) { - printDetail(dfPlayer.readType(), dfPlayer.read()); //Print the detail message from DFPlayer to handle different errors and states. + if (dfPlayer.available()) + { + printDetail(dfPlayer.readType(), dfPlayer.read()); // Print the detail message from DFPlayer to handle different errors and states. } -} // end - - - +} // end // Functions to learn DFPlayer behavior -void playNotBusy() { - //Plays all files succsivly. +void playNotBusy() +{ + // Plays all files succsivly. Serial.println("PlayNotBusy"); - if (HIGH == digitalRead(nDFPlayer_BUSY)) { - //mp3_next (); + if (HIGH == digitalRead(nDFPlayer_BUSY)) + { + // mp3_next (); dfPlayer.next(); - } - if (dfPlayer.available()) { - printDetail(dfPlayer.readType(), dfPlayer.read()); //Print the detail message from DFPlayer to handle different errors and states. + if (dfPlayer.available()) + { + printDetail(dfPlayer.readType(), dfPlayer.read()); // Print the detail message from DFPlayer to handle different errors and states. } - delay(1000); //This should be removed from code. We set a time for the next allowed message. + delay(1000); // This should be removed from code. We set a time for the next allowed message. // Or better yet use interupt to find the end of BUSY and set time for the next allowed DFPlayer message -} // end playNotBusy +} // end playNotBusy -void playNotBusyLevel(int level) { - //Plays all files succsivly. +void playNotBusyLevel(int level) +{ + // Plays all files succsivly. Serial.println("PlayNotBusyLevel"); - if (HIGH == digitalRead(nDFPlayer_BUSY)) { - //mp3_next (); - // Note....we should in fact use file names, not numbers here, - // or must at least build a data structure to associate the two. - // that shoulde be future work. - dfPlayer.play(level+1); + if (HIGH == digitalRead(nDFPlayer_BUSY)) + { + // mp3_next (); + // Note....we should in fact use file names, not numbers here, + // or must at least build a data structure to associate the two. + // that shoulde be future work. + dfPlayer.play(level + 1); Serial.println("HIGH .next called! ================="); - } - if (dfPlayer.available()) { - printDetail(dfPlayer.readType(), dfPlayer.read()); //Print the detail message from DFPlayer to handle different errors and states. } - delay(1000); //This should be removed from code. We set a time for the next allowed message. + if (dfPlayer.available()) + { + printDetail(dfPlayer.readType(), dfPlayer.read()); // Print the detail message from DFPlayer to handle different errors and states. + } + delay(1000); // This should be removed from code. We set a time for the next allowed message. // Or better yet use interupt to find the end of BUSY and set time for the next allowed DFPlayer message } - // Play a track but not if the DFPlayer is busy -bool playAlarmLevel(int alarmNumberToPlay) { +bool playAlarmLevel(int alarmNumberToPlay) +{ static unsigned long timer = millis(); const unsigned long delayPlayLevel = 20; // const int MAX_ALARM_NUMBER = 6; int tracNumber = alarmNumberToPlay; - if (millis() - timer > delayPlayLevel) { + if (millis() - timer > delayPlayLevel) + { // if (millis() - timer > 10000) { timer = millis(); - //If not busy play the alarm message - if ((0 > tracNumber < 0) || (numberFilesDF < tracNumber)) { + // If not busy play the alarm message + if ((0 > tracNumber < 0) || (numberFilesDF < tracNumber)) + { return false; - } else //Valid track number - if (HIGH == digitalRead(nDFPlayer_BUSY)) { // Should the test for busy be at the start of this function??? - //mp3_next (); + } + else // Valid track number + if (HIGH == digitalRead(nDFPlayer_BUSY)) + { // Should the test for busy be at the start of this function??? + // mp3_next (); dfPlayer.play(tracNumber); - } else { + } + else + { Serial.println("Not done playing previous file"); } - if (dfPlayer.available()) { - printDetail(dfPlayer.readType(), dfPlayer.read()); //Print the detail message from DFPlayer to handle different errors and states. + if (dfPlayer.available()) + { + printDetail(dfPlayer.readType(), dfPlayer.read()); // Print the detail message from DFPlayer to handle different errors and states. } return true; - } else { + } + else + { return false; } -} // end of playAlarmLevel - +} // end of playAlarmLevel // void setupDFP() { // pinMode(LED_PIN, OUTPUT); @@ -362,4 +389,3 @@ bool playAlarmLevel(int alarmNumberToPlay) { // Serial.println("End of setup"); // digitalWrite(LED_PIN, LOW); // } // end of setup() - diff --git a/Firmware/GPAD_API/src/DFPlayer.h b/Firmware/GPAD_API/src/DFPlayer.h index b6d2debd..f8f2866c 100644 --- a/Firmware/GPAD_API/src/DFPlayer.h +++ b/Firmware/GPAD_API/src/DFPlayer.h @@ -2,7 +2,7 @@ #define DFPLAYER 1 #include -#define BAUD_DFPLAYER 9600 //for UART2 to the DFPlayer +#define BAUD_DFPLAYER 9600 // for UART2 to the DFPlayer #define TXD2 17 #define RXD2 16 diff --git a/Firmware/GPAD_API/src/GPAD_API.ino b/Firmware/GPAD_API/src/GPAD_API.ino index 6f8b7e48..2d8f2f79 100644 --- a/Firmware/GPAD_API/src/GPAD_API.ino +++ b/Firmware/GPAD_API/src/GPAD_API.ino @@ -63,7 +63,7 @@ #include // From library https://github.com/knolleary/ #include // WiFi Manager for ESP32 -#include "LittleFS.h" +#include #include #include // File System Support #include // req for i2c comm diff --git a/Firmware/GPAD_API/src/GPAD_HAL.cpp b/Firmware/GPAD_API/src/GPAD_HAL.cpp index f142d064..0de718ac 100644 --- a/Firmware/GPAD_API/src/GPAD_HAL.cpp +++ b/Firmware/GPAD_API/src/GPAD_HAL.cpp @@ -18,7 +18,7 @@ */ -//#include +// #include #include "GPAD_HAL.h" #include "alarm_api.h" #include "gpad_utility.h" @@ -29,9 +29,8 @@ extern IPAddress myIP; // Use Serial1 for UART communication -HardwareSerial uartSerial1(1); //For user Serial Port -HardwareSerial uartSerial2(2); //For DFPLayer, audio - +HardwareSerial uartSerial1(1); // For user Serial Port +HardwareSerial uartSerial2(2); // For DFPLayer, audio #include // Time in ms you need to hold down the button to be considered a long press @@ -44,7 +43,6 @@ unsigned int multiHitTime = 400; DailyStruggleButton muteButton; DailyStruggleButton encoderSwitchButton; - extern const char *AlarmNames[]; extern AlarmLevel currentLevel; extern bool currentlyMuted; @@ -55,25 +53,25 @@ extern char macAddressString[13]; // TODO: Remove this; for explanation only extern char publish_Ack_Topic[17]; -#include // From library https://github.com/knolleary/pubsubclient +#include // From library https://github.com/knolleary/pubsubclient extern PubSubClient client; -//For LCD -// #include +// For LCD +// #include // https://github.com/johnrickman/LiquidCrystal_I2C LiquidCrystal_I2C lcd(LCD_ADDRESS, 20, 4); #include "DFPlayer.h" -//Setup for buzzer. -//const int BUZZER_TEST_FREQ = 130; // One below middle C3. About 67 db, 3" x 4.875" 8 Ohm speakers no cabinet at 1 Meter. -//const int BUZZER_TEST_FREQ = 260; // Middle C4. About ?? db, 3" x 4.875" 8 Ohm speakers no cabinet at 1 Meter. -//const int BUZZER_TEST_FREQ = 1000; //About 76 db, 3" x 4.875" 8 Ohm speakers no cabinet at 1 Meter. -const int BUZZER_TEST_FREQ = 4000; // Buzzers, 3 V 4kHz 60dB @ 3V, 10 cm. The specified frequencey for the Version 1 buzzer. +// Setup for buzzer. +// const int BUZZER_TEST_FREQ = 130; // One below middle C3. About 67 db, 3" x 4.875" 8 Ohm speakers no cabinet at 1 Meter. +// const int BUZZER_TEST_FREQ = 260; // Middle C4. About ?? db, 3" x 4.875" 8 Ohm speakers no cabinet at 1 Meter. +// const int BUZZER_TEST_FREQ = 1000; //About 76 db, 3" x 4.875" 8 Ohm speakers no cabinet at 1 Meter. +const int BUZZER_TEST_FREQ = 4000; // Buzzers, 3 V 4kHz 60dB @ 3V, 10 cm. The specified frequencey for the Version 1 buzzer. -const int BUZZER_LVL_FREQ_HZ[] = { 0, 128, 256, 512, 1024, 2048 }; +const int BUZZER_LVL_FREQ_HZ[] = {0, 128, 256, 512, 1024, 2048}; // This as an attempt to program recognizable "songs" for each alarm level that accomplish // both informativeness and urgency mapping. The is is to use an index into the buzzer @@ -82,32 +80,30 @@ const int BUZZER_LVL_FREQ_HZ[] = { 0, 128, 256, 512, 1024, 2048 }; // give us a 6-second repeat. const unsigned int NUM_NOTES = 20; -const int SONGS[][NUM_NOTES] = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 }, - { 2, 2, 0, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 0, 2, 2, 0, 0, 0, 0 }, - { 3, 3, 3, 0, 3, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 0, 0, 0 }, - { 4, 0, 4, 0, 4, 0, 4, 0, 0, 0, 4, 0, 4, 0, 4, 0, 4, 0, 0, 0 }, - { 4, 4, 2, 0, 4, 4, 2, 0, 4, 4, 2, 0, 4, 4, 2, 0, 4, 4, 2, 0 } }; - -const int LIGHT_LEVEL[][NUM_NOTES] = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 }, - { 2, 2, 0, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 0, 2, 2, 0, 0, 0, 0 }, - { 3, 3, 3, 0, 3, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 0, 0, 0 }, - { 4, 4, 4, 0, 4, 4, 4, 0, 0, 0, 4, 4, 4, 0, 4, 4, 4, 0, 0, 0 }, - { 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5 } }; +const int SONGS[][NUM_NOTES] = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}, + {2, 2, 0, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 0, 2, 2, 0, 0, 0, 0}, + {3, 3, 3, 0, 3, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 0, 0, 0}, + {4, 0, 4, 0, 4, 0, 4, 0, 0, 0, 4, 0, 4, 0, 4, 0, 4, 0, 0, 0}, + {4, 4, 2, 0, 4, 4, 2, 0, 4, 4, 2, 0, 4, 4, 2, 0, 4, 4, 2, 0}}; + +const int LIGHT_LEVEL[][NUM_NOTES] = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}, + {2, 2, 0, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 0, 2, 2, 0, 0, 0, 0}, + {3, 3, 3, 0, 3, 3, 3, 3, 0, 3, 3, 3, 0, 3, 3, 3, 0, 0, 0, 0}, + {4, 4, 4, 0, 4, 4, 4, 0, 0, 0, 4, 4, 4, 0, 4, 4, 4, 0, 0, 0}, + {0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5}}; const unsigned LEN_OF_NOTE_MS = 500; unsigned long start_of_song = 0; - - // in general, we want tones to last forever, although // I may implement blinking later. const unsigned long INF_DURATION = 4294967295; -//Allow indexing to LIGHT[] by symbolic name. So LIGHT0 is first and so on. -int LIGHT[] = { LIGHT0, LIGHT1, LIGHT2, LIGHT3, LIGHT4 }; +// Allow indexing to LIGHT[] by symbolic name. So LIGHT0 is first and so on. +int LIGHT[] = {LIGHT0, LIGHT1, LIGHT2, LIGHT3, LIGHT4}; int NUM_LIGHTS = sizeof(LIGHT) / sizeof(LIGHT[0]); Stream *local_ptr_to_serial; @@ -123,98 +119,107 @@ byte received_signal_raw_bytes[MAX_BUFFER_SIZE]; // Local DEBUG defines, GPAD_HAL #define DEBUG 0 -//#define DEBUG 1 +// #define DEBUG 1 #if (DEBUG > 0) Serial.println("Debug defined >0") #endif - const int NUM_PREFICES = 5; -char legal_prefices[NUM_PREFICES] = { 'h', 's', 'a', 'u', 'i' }; - + const int NUM_PREFICES = 5; +char legal_prefices[NUM_PREFICES] = {'h', 's', 'a', 'u', 'i'}; -void setup_spi() { +void setup_spi() +{ Serial.println(F("Starting SPI Peripheral.")); Serial.print(F("Pin for SS: ")); Serial.println(SS); - pinMode(BUTTON_PIN, INPUT); // Setting pin 2 as INPUT - pinMode(LED_PIN, OUTPUT); // Setting pin 7 as OUTPUT + pinMode(BUTTON_PIN, INPUT); // Setting pin 2 as INPUT + pinMode(LED_PIN, OUTPUT); // Setting pin 7 as OUTPUT // SPI.begin(); // IMPORTANT. Do not set SPI.begin for a peripherial device. - pinMode(SS, INPUT_PULLUP); //Sets SS as input for peripherial + pinMode(SS, INPUT_PULLUP); // Sets SS as input for peripherial // Why is this not input? - pinMode(MOSI, INPUT); //This works for Peripheral - pinMode(MISO, OUTPUT); //try this. - pinMode(SCK, INPUT); //Sets clock as input + pinMode(MOSI, INPUT); // This works for Peripheral + pinMode(MISO, OUTPUT); // try this. + pinMode(SCK, INPUT); // Sets clock as input #if defined(GPAD) - SPCR |= _BV(SPE); //Turn on SPI in Peripheral Mode + SPCR |= _BV(SPE); // Turn on SPI in Peripheral Mode // turn on interrupts SPCR |= _BV(SPIE); isReceived_SPI = false; - SPI.attachInterrupt(); //Interuupt ON is set for SPI commnucation + SPI.attachInterrupt(); // Interuupt ON is set for SPI commnucation #else #endif -} //end setup_SPI() +} // end setup_SPI() -//ISRs -// This is the original... -// I plan to add an index to this to handle the full message that we intend to receive. -// However, I think this also needs a timeout to handle the problem of getting out of synch. -const int SPI_BYTE_TIMEOUT_MS = 200; // we don't get the next byte this fast, we reset. +// ISRs +// This is the original... +// I plan to add an index to this to handle the full message that we intend to receive. +// However, I think this also needs a timeout to handle the problem of getting out of synch. +const int SPI_BYTE_TIMEOUT_MS = 200; // we don't get the next byte this fast, we reset. volatile unsigned long last_byte_ms = 0; #if defined(HMWK) // void IRAM_ATTR ISR() { // receive_byte(SPDR); // } -#elif defined(GPAD) // compile for an UNO, for example... -ISR(SPI_STC_vect) //Inerrrput routine function +#elif defined(GPAD) // compile for an UNO, for example... +ISR(SPI_STC_vect) // Inerrrput routine function { receive_byte(SPDR); -} //end ISR +} // end ISR #endif - - -void receive_byte(byte c) { +void receive_byte(byte c) +{ last_byte_ms = millis(); // byte c = SPDR; // read byte from SPI Data Register - if (indx < sizeof received_signal_raw_bytes) { - received_signal_raw_bytes[indx] = c; // save data in the next index in the array received_signal_raw_bytes + if (indx < sizeof received_signal_raw_bytes) + { + received_signal_raw_bytes[indx] = c; // save data in the next index in the array received_signal_raw_bytes indx = indx + 1; } - if (indx >= sizeof received_signal_raw_bytes) { + if (indx >= sizeof received_signal_raw_bytes) + { process = true; } } - -void updateFromSPI() { - if (DEBUG > 0) { - if (process) { +void updateFromSPI() +{ + if (DEBUG > 0) + { + if (process) + { Serial.println("process true!"); } } - if (process) { + if (process) + { AlarmEvent event; event.lvl = (AlarmLevel)received_signal_raw_bytes[0]; - for (int i = 0; i < MAX_MSG_LEN; i++) { + for (int i = 0; i < MAX_MSG_LEN; i++) + { event.msg[i] = (char)received_signal_raw_bytes[1 + i]; } - if (DEBUG > 1) { + if (DEBUG > 1) + { Serial.print(F("LVL: ")); Serial.println(event.lvl); Serial.println(event.msg); } int prevLevel = alarm((AlarmLevel)event.lvl, event.msg, &Serial); - if (prevLevel != event.lvl) { + if (prevLevel != event.lvl) + { annunciateAlarmLevel(&Serial); - } else { + } + else + { unchanged_anunicateAlarmLevel(&Serial); } @@ -225,100 +230,105 @@ void updateFromSPI() { // Have to get a serialport here -//void myCallback(byte buttonEvent) { -void encoderSwitchCallback(byte buttonEvent) { - switch (buttonEvent) { - case onPress: - // Do something... - local_ptr_to_serial->println(F("ENCODER_SWITCH onPress")); - // currentlyMuted = !currentlyMuted; - // start_of_song = millis(); - // annunciateAlarmLevel(local_ptr_to_serial); - // printAlarmState(local_ptr_to_serial); - - registerRotaryEncoderPress(); - break; - case onRelease: - // Do nothing... - local_ptr_to_serial->println(F("ENCODER_SWITCH onRelease")); - break; - case onHold: - // Do nothing... - //local_ptr_to_serial->println(F("ENCODER_SWITCH onHold")); - break; - // onLongPress is indidcated when you hold onto the button - // more than longPressTime in milliseconds - case onLongPress: - Serial.print("ENCODER_SWITCH Button Long Pressed For "); - Serial.print(longPressTime); - Serial.println("ms"); - break; - - // onMultiHit is indicated when you hit the button - // multiHitTarget times within multihitTime in milliseconds - case onMultiHit: - Serial.print("Encoder Switch Button Pressed "); - Serial.print(multiHitTarget); - Serial.print(" times in "); - Serial.print(multiHitTime); - Serial.println("ms"); - break; - default: - Serial.print("Encoder Switch buttonEvent but not reckognized case: "); - Serial.println(buttonEvent); - break; +// void myCallback(byte buttonEvent) { +void encoderSwitchCallback(byte buttonEvent) +{ + switch (buttonEvent) + { + case onPress: + // Do something... + local_ptr_to_serial->println(F("ENCODER_SWITCH onPress")); + // currentlyMuted = !currentlyMuted; + // start_of_song = millis(); + // annunciateAlarmLevel(local_ptr_to_serial); + // printAlarmState(local_ptr_to_serial); + + registerRotaryEncoderPress(); + break; + case onRelease: + // Do nothing... + local_ptr_to_serial->println(F("ENCODER_SWITCH onRelease")); + break; + case onHold: + // Do nothing... + // local_ptr_to_serial->println(F("ENCODER_SWITCH onHold")); + break; + // onLongPress is indidcated when you hold onto the button + // more than longPressTime in milliseconds + case onLongPress: + Serial.print("ENCODER_SWITCH Button Long Pressed For "); + Serial.print(longPressTime); + Serial.println("ms"); + break; + + // onMultiHit is indicated when you hit the button + // multiHitTarget times within multihitTime in milliseconds + case onMultiHit: + Serial.print("Encoder Switch Button Pressed "); + Serial.print(multiHitTarget); + Serial.print(" times in "); + Serial.print(multiHitTime); + Serial.println("ms"); + break; + default: + Serial.print("Encoder Switch buttonEvent but not reckognized case: "); + Serial.println(buttonEvent); + break; } } // Have to get a serialport here -//void myCallback(byte buttonEvent) { -void muteButtonCallback(byte buttonEvent) { - switch (buttonEvent) { - case onPress: - // Do something... - local_ptr_to_serial->println(F("SWITCH_MUTE onPress")); - currentlyMuted = !currentlyMuted; - start_of_song = millis(); - annunciateAlarmLevel(local_ptr_to_serial); - printAlarmState(local_ptr_to_serial); - break; - case onRelease: - // Do nothing... - local_ptr_to_serial->println(F("SWITCH_MUTE onRelease")); - break; - case onHold: - // Do nothing... - local_ptr_to_serial->println(F("SWITCH_MUTE onHold")); - break; - // onLongPress is indidcated when you hold onto the button - // more than longPressTime in milliseconds - case onLongPress: - Serial.print("SWITCH_MUTE Long Pressed For "); - Serial.print(longPressTime); - Serial.println("ms"); - break; - - // onMultiHit is indicated when you hit the button - // multiHitTarget times within multihitTime in milliseconds - case onMultiHit: - Serial.print("Button Pressed "); - Serial.print(multiHitTarget); - Serial.print(" times in "); - Serial.print(multiHitTime); - Serial.println("ms"); - break; - default: - Serial.print("Mute buttonEvent but not reckognized case: "); - Serial.println(buttonEvent); - break; +// void myCallback(byte buttonEvent) { +void muteButtonCallback(byte buttonEvent) +{ + switch (buttonEvent) + { + case onPress: + // Do something... + local_ptr_to_serial->println(F("SWITCH_MUTE onPress")); + currentlyMuted = !currentlyMuted; + start_of_song = millis(); + annunciateAlarmLevel(local_ptr_to_serial); + printAlarmState(local_ptr_to_serial); + break; + case onRelease: + // Do nothing... + local_ptr_to_serial->println(F("SWITCH_MUTE onRelease")); + break; + case onHold: + // Do nothing... + local_ptr_to_serial->println(F("SWITCH_MUTE onHold")); + break; + // onLongPress is indidcated when you hold onto the button + // more than longPressTime in milliseconds + case onLongPress: + Serial.print("SWITCH_MUTE Long Pressed For "); + Serial.print(longPressTime); + Serial.println("ms"); + break; + + // onMultiHit is indicated when you hit the button + // multiHitTarget times within multihitTime in milliseconds + case onMultiHit: + Serial.print("Button Pressed "); + Serial.print(multiHitTarget); + Serial.print(" times in "); + Serial.print(multiHitTime); + Serial.println("ms"); + break; + default: + Serial.print("Mute buttonEvent but not reckognized case: "); + Serial.println(buttonEvent); + break; } } -void GPAD_HAL_setup(Stream *serialport) { - //Setup and present LCD splash screen - //Setup the SWITCH_MUTE - //Setup the SWITCH_ENCODER - //Print instructions on DEBUG serial port +void GPAD_HAL_setup(Stream *serialport) +{ + // Setup and present LCD splash screen + // Setup the SWITCH_MUTE + // Setup the SWITCH_ENCODER + // Print instructions on DEBUG serial port local_ptr_to_serial = serialport; Wire.begin(); @@ -334,16 +344,16 @@ void GPAD_HAL_setup(Stream *serialport) { splashLCD(); - #if (DEBUG > 0) serialport->println(F("EndLCD splash")); #endif - //Setup GPIO pins, Mute and lights - pinMode(SWITCH_MUTE, INPUT_PULLUP); //The SWITCH_MUTE is different on Atmega vs ESP32. Is this redundant? - pinMode(SWITCH_ENCODER, INPUT_PULLUP); //The SWITCH_ENCODER is new to Krake. Is this redundant? + // Setup GPIO pins, Mute and lights + pinMode(SWITCH_MUTE, INPUT_PULLUP); // The SWITCH_MUTE is different on Atmega vs ESP32. Is this redundant? + pinMode(SWITCH_ENCODER, INPUT_PULLUP); // The SWITCH_ENCODER is new to Krake. Is this redundant? - for (int i = 0; i < NUM_LIGHTS; i++) { + for (int i = 0; i < NUM_LIGHTS; i++) + { #if (DEBUG > 0) serialport->print(LIGHT[i]); serialport->print(", "); @@ -351,7 +361,7 @@ void GPAD_HAL_setup(Stream *serialport) { pinMode(LIGHT[i], OUTPUT); // Rob trying to prevent resets // This is necessary on SN#3 - digitalWrite(LIGHT[i],LOW); + digitalWrite(LIGHT[i], LOW); } serialport->println(""); @@ -359,8 +369,8 @@ void GPAD_HAL_setup(Stream *serialport) { muteButton.enableLongPress(longPressTime); muteButton.enableMultiHit(multiHitTime, multiHitTarget); - //SW4.set(GPIO_SW4, SendEmergMessage, INT_PULL_UP); - // encoderSwitchButton.set(SWITCH_ENCODER, encoderSwitchCallback, INT_PULL_UP); + // SW4.set(GPIO_SW4, SendEmergMessage, INT_PULL_UP); + // encoderSwitchButton.set(SWITCH_ENCODER, encoderSwitchCallback, INT_PULL_UP); encoderSwitchButton.set(SWITCH_ENCODER, encoderSwitchCallback); encoderSwitchButton.enableLongPress(longPressTime); encoderSwitchButton.enableMultiHit(multiHitTime, multiHitTarget); @@ -370,12 +380,12 @@ void GPAD_HAL_setup(Stream *serialport) { // digitalWrite(LED_BUILTIN, LOW); // turn the LED off at end of setup -#if !defined(HMWK) //On Homework2, LCD goes blank early +#if !defined(HMWK) // On Homework2, LCD goes blank early // Here initialize the UART1 - //FLE the Serial1 is faliing to terminate + // FLE the Serial1 is faliing to terminate // pinMode(RXD1, INPUT_PULLUP); - uartSerial1.begin(UART1_BAUD_RATE, SERIAL_8N1, RXD1, TXD1); // UART setup. On Homework2, LCD goes blank early - uartSerial1.flush(); //Clear any Serial1 crud at reset. + uartSerial1.begin(UART1_BAUD_RATE, SERIAL_8N1, RXD1, TXD1); // UART setup. On Homework2, LCD goes blank early + uartSerial1.flush(); // Clear any Serial1 crud at reset. #if (DEBUG > 0) serialport->println(F("uartSerial1 Setup")); @@ -384,28 +394,33 @@ void GPAD_HAL_setup(Stream *serialport) { // Here initialize the UART2 pinMode(RXD2, INPUT_PULLUP); - uartSerial2.begin(UART2_BAUD_RATE, SERIAL_8N1, RXD2, TXD2); // UART setup + uartSerial2.begin(UART2_BAUD_RATE, SERIAL_8N1, RXD2, TXD2); // UART setup uartSerial2.flush(); #if (DEBUG > 0) serialport->println(F("uartSerial2 Setup")); #endif -} // end GPAD_HAL_setup() +} // end GPAD_HAL_setup() // This routine should be refactored so that it only "interprets" // the character buffer and returns an "abstract" command to be acted on // elseshere. This will allow us to remove the PubSubClient from the this file, // the Hardware Abstraction Layer. -void interpretBuffer(char *buf, int rlen, Stream *serialport, PubSubClient *client) { - if (rlen < 1) { +void interpretBuffer(char *buf, int rlen, Stream *serialport, PubSubClient *client) +{ + if (rlen < 1) + { printError(serialport); - return; // no action + return; // no action } bool found = false; - for (int i = 0; i < NUM_PREFICES; i++) { - if (buf[0] == legal_prefices[i]) found = true; + for (int i = 0; i < NUM_PREFICES; i++) + { + if (buf[0] == legal_prefices[i]) + found = true; } - if (!found) { + if (!found) + { printError(serialport); return; } @@ -413,128 +428,132 @@ void interpretBuffer(char *buf, int rlen, Stream *serialport, PubSubClient *clie serialport->print(F("Command: ")); serialport->println(C); - switch (C) { - case 's': - serialport->println(F("Muting Case!")); - currentlyMuted = true; - break; - case 'u': - serialport->println(F("UnMuting Case!")); - currentlyMuted = false; - break; - case 'h': // help - printInstructions(serialport); - break; - case 'a': - { - // In the case of an alarm state, the rest of the buffer is a message. - // we will read up to 60 characters from this buffer for display on our - // Arguably when we support mulitple states this will become more complicated. - char D = buf[1]; - int N = D - '0'; - serialport->println(N); - // WARNING: Shouldn't this be MAX_BUFFER_SIZE? - char msg[61]; - msg[0] = '\0'; - strncat(msg, buf, 60); - // This copy loooks uncessary, but is not...we want "alarm" - // to be a completely independent and abstract function. - // it should copy the msg buffer - serialport->print("The MQTT Alarm Message: "); - serialport->println(msg); - alarm((AlarmLevel)N, msg, serialport); //Makes Lamps indicate alarm. - - break; - } - case 'i': //Information. Firmware Version, Mute Status, - { - //Firmware Version - // 81+23 = Maximum string length - // char onInfoMsg[32] = "Firmware Version: "; - // static char onInfoMsg[81+24] = "Firmware Version: "; //This does not have the bug. - char onInfoMsg[81 + 24] = "Firmware Version: "; //This - char str[20]; - - strcat(onInfoMsg, FIRMWARE_VERSION); - client->publish(publish_Ack_Topic, onInfoMsg); - serialport->println(onInfoMsg); - - //Up time - onInfoMsg[0] = '\0'; - - str[0] = '\0'; - strcat(onInfoMsg, "System up time (mills): "); - sprintf(str, "%d", millis()); - strcat(onInfoMsg, str); - client->publish(publish_Ack_Topic, onInfoMsg); - serialport->println(onInfoMsg); - - // Mute status - onInfoMsg[0] = '\0'; - //onInfoMsg[32] = "Mute Status: "; - strcat(onInfoMsg, "Mute Status: "); - if (currentlyMuted) { - strcat(onInfoMsg, "MUTED"); - } else { - strcat(onInfoMsg, "NOT MUTED"); - } - client->publish(publish_Ack_Topic, onInfoMsg); - serialport->println(onInfoMsg); - - //Alarm level - onInfoMsg[0] = '\0'; - str[0] = '\0'; - strcat(onInfoMsg, "Current alarm Level: "); - sprintf(str, "%d", getCurrentAlarmLevel()); - strcat(onInfoMsg, str); - client->publish(publish_Ack_Topic, onInfoMsg); - serialport->println(onInfoMsg); - - //Alarm message - onInfoMsg[0] = '\0'; - strcat(onInfoMsg, "Current alarm message: "); - // strcat(onInfoMsg, *getCurrentMessage()); Produced error error: invalid conversion from 'char' to 'const char*' [-fpermissive] - strcat(onInfoMsg, getCurrentMessage()); - client->publish(publish_Ack_Topic, onInfoMsg); - serialport->println(onInfoMsg); - - //IP Address - //Serial.println(WiFi.localIP()); - - onInfoMsg[0] = '\0'; - strcat(onInfoMsg, "IP Address: "); - // //strcat(onInfoMsg, myIP.toString()); //This returns Compilation error: request for member 'toString' in 'myIP', which is of non-class type 'IPAddress()' - - char ipString[] = "(0,0,0,0)"; - // // sprintf(ipString, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); - // sprintf(ipString, "%d.%d.%d.%d", myIP[0], myIP[1], myIP[2], myIP[3]); - - strcat(onInfoMsg, ipString); //This returns Compilation error: request for member 'toString' in 'myIP', which is of non-class type 'IPAddress()' - - client->publish(publish_Ack_Topic, onInfoMsg); - serialport->println(onInfoMsg); - - // serialport->print("myIP ="); - // serialport->println(myIP); // Caused Error Multiple libraries were found for "WiFiManager.h" - - break; //end of 'i' - } - default: - serialport->println(F("Unknown Command")); - break; + switch (C) + { + case 's': + serialport->println(F("Muting Case!")); + currentlyMuted = true; + break; + case 'u': + serialport->println(F("UnMuting Case!")); + currentlyMuted = false; + break; + case 'h': // help + printInstructions(serialport); + break; + case 'a': + { + // In the case of an alarm state, the rest of the buffer is a message. + // we will read up to 60 characters from this buffer for display on our + // Arguably when we support mulitple states this will become more complicated. + char D = buf[1]; + int N = D - '0'; + serialport->println(N); + // WARNING: Shouldn't this be MAX_BUFFER_SIZE? + char msg[61]; + msg[0] = '\0'; + strncat(msg, buf, 60); + // This copy loooks uncessary, but is not...we want "alarm" + // to be a completely independent and abstract function. + // it should copy the msg buffer + serialport->print("The MQTT Alarm Message: "); + serialport->println(msg); + alarm((AlarmLevel)N, msg, serialport); // Makes Lamps indicate alarm. + + break; + } + case 'i': // Information. Firmware Version, Mute Status, + { + // Firmware Version + // 81+23 = Maximum string length + // char onInfoMsg[32] = "Firmware Version: "; + // static char onInfoMsg[81+24] = "Firmware Version: "; //This does not have the bug. + char onInfoMsg[81 + 24] = "Firmware Version: "; // This + char str[20]; + + strcat(onInfoMsg, FIRMWARE_VERSION); + client->publish(publish_Ack_Topic, onInfoMsg); + serialport->println(onInfoMsg); + + // Up time + onInfoMsg[0] = '\0'; + + str[0] = '\0'; + strcat(onInfoMsg, "System up time (mills): "); + sprintf(str, "%d", millis()); + strcat(onInfoMsg, str); + client->publish(publish_Ack_Topic, onInfoMsg); + serialport->println(onInfoMsg); + + // Mute status + onInfoMsg[0] = '\0'; + // onInfoMsg[32] = "Mute Status: "; + strcat(onInfoMsg, "Mute Status: "); + if (currentlyMuted) + { + strcat(onInfoMsg, "MUTED"); + } + else + { + strcat(onInfoMsg, "NOT MUTED"); + } + client->publish(publish_Ack_Topic, onInfoMsg); + serialport->println(onInfoMsg); + + // Alarm level + onInfoMsg[0] = '\0'; + str[0] = '\0'; + strcat(onInfoMsg, "Current alarm Level: "); + sprintf(str, "%d", getCurrentAlarmLevel()); + strcat(onInfoMsg, str); + client->publish(publish_Ack_Topic, onInfoMsg); + serialport->println(onInfoMsg); + + // Alarm message + onInfoMsg[0] = '\0'; + strcat(onInfoMsg, "Current alarm message: "); + // strcat(onInfoMsg, *getCurrentMessage()); Produced error error: invalid conversion from 'char' to 'const char*' [-fpermissive] + strcat(onInfoMsg, getCurrentMessage()); + client->publish(publish_Ack_Topic, onInfoMsg); + serialport->println(onInfoMsg); + + // IP Address + // Serial.println(WiFi.localIP()); + + onInfoMsg[0] = '\0'; + strcat(onInfoMsg, "IP Address: "); + // //strcat(onInfoMsg, myIP.toString()); //This returns Compilation error: request for member 'toString' in 'myIP', which is of non-class type 'IPAddress()' + + char ipString[] = "(0,0,0,0)"; + // // sprintf(ipString, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); + // sprintf(ipString, "%d.%d.%d.%d", myIP[0], myIP[1], myIP[2], myIP[3]); + + strcat(onInfoMsg, ipString); // This returns Compilation error: request for member 'toString' in 'myIP', which is of non-class type 'IPAddress()' + + client->publish(publish_Ack_Topic, onInfoMsg); + serialport->println(onInfoMsg); + + // serialport->print("myIP ="); + // serialport->println(myIP); // Caused Error Multiple libraries were found for "WiFiManager.h" + + break; // end of 'i' + } + default: + serialport->println(F("Unknown Command")); + break; } serialport->print(F("currentlyMuted : ")); serialport->println(currentlyMuted); serialport->println(F("interpret Done")); - //FLE delay(3000); -} //end interpretBuffer() - + // FLE delay(3000); +} // end interpretBuffer() // This has to be called periodically, at a minimum to handle the mute_button -void GPAD_HAL_loop() { +void GPAD_HAL_loop() +{ muteButton.poll(); encoderSwitchButton.poll(); -#if defined(GPAD) //FLE??? Why is this conditional compile? +#if defined(GPAD) // FLE??? Why is this conditional compile? muteButton.poll(); #endif } @@ -544,22 +563,24 @@ void GPAD_HAL_loop() { Clears display Turns on back light. */ -void clearLCD(void) { +void clearLCD(void) +{ lcd.noBacklight(); lcd.clear(); } -//Splash a message so we can tell the LCD is working -void splashLCD(void) { - lcd.init(); // initialize the lcd +// Splash a message so we can tell the LCD is working +void splashLCD(void) +{ + lcd.init(); // initialize the lcd // Print a message to the LCD. -//#if (!LIMIT_POWER_DRAW) + // #if (!LIMIT_POWER_DRAW) lcd.backlight(); -//#else -// lcd.noBacklight(); -//#endif + // #else + // lcd.noBacklight(); + // #endif - //Line 0 + // Line 0 lcd.setCursor(0, 0); lcd.print(MODEL_NAME); // lcd.print(DEVICE_UNDER_TEST); @@ -568,31 +589,35 @@ void splashLCD(void) { lcd.print(" "); lcd.print(FIRMWARE_VERSION); - //Line 1 + // Line 1 lcd.setCursor(0, 1); lcd.print("IP: " + WiFi.localIP().toString()); - //Line 2 + // Line 2 lcd.setCursor(0, 2); lcd.print(F(__DATE__ " " __TIME__)); - //Line 3 + // Line 3 lcd.setCursor(0, 3); lcd.print("MAC: "); lcd.print(macAddressString); } -bool printable(char c) { +bool printable(char c) +{ return isPrintable(c) || (c == ' '); } // Remove unwanted characters.... -void filter_control_chars(char *msg) { +void filter_control_chars(char *msg) +{ size_t len = strlen(msg); char buff[MAX_BUFFER_SIZE]; strcpy(buff, msg); int k = 0; - for (int i = 0; i < len; i++) { + for (int i = 0; i < len; i++) + { char c = buff[i]; - if (printable(c)) { + if (printable(c)) + { msg[k] = c; k++; } @@ -601,15 +626,19 @@ void filter_control_chars(char *msg) { } // TODO: We need to break the message up into strings to render properly // on the display -void showStatusLCD(AlarmLevel level, bool muted, char *msg) { +void showStatusLCD(AlarmLevel level, bool muted, char *msg) +{ lcd.init(); lcd.clear(); // Possibly we don't need the backlight if the level is zero! - if (level != 0) { -// #if (!LIMIT_POWER_DRAW) + if (level != 0) + { + // #if (!LIMIT_POWER_DRAW) lcd.backlight(); -// #endif - } else { + // #endif + } + else + { lcd.noBacklight(); } @@ -621,27 +650,35 @@ void showStatusLCD(AlarmLevel level, bool muted, char *msg) { int msgLineStart = 1; lcd.setCursor(0, msgLineStart); int len = strlen(AlarmMessageBuffer); - if (len < 9) { - if (muted) { + if (len < 9) + { + if (muted) + { lcd.print("MUTED! MSG:"); - } else { + } + else + { lcd.print("MSG: "); } msgLineStart = 2; } - if (strlen(AlarmMessageBuffer) == 0) { + if (strlen(AlarmMessageBuffer) == 0) + { lcd.print("None."); - } else { + } + else + { - char buffer[21] = { 0 }; // note space for terminator - // filter unmeaningful characters from msg buffer + char buffer[21] = {0}; // note space for terminator + // filter unmeaningful characters from msg buffer filter_control_chars(msg); - size_t len = strlen(msg); // doesn't count terminator - size_t blen = sizeof(buffer) - 1; // doesn't count terminator + size_t len = strlen(msg); // doesn't count terminator + size_t blen = sizeof(buffer) - 1; // doesn't count terminator size_t i = 0; // the actual loop that enumerates your buffer - for (i = 0; i < (len / blen + 1) && i + msgLineStart < 4; ++i) { + for (i = 0; i < (len / blen + 1) && i + msgLineStart < 4; ++i) + { memcpy(buffer, msg + (i * blen), blen); local_ptr_to_serial->println(buffer); lcd.setCursor(0, i + msgLineStart); @@ -651,53 +688,63 @@ void showStatusLCD(AlarmLevel level, bool muted, char *msg) { } // This operation is idempotent if there is no change in the abstract state. -void set_light_level(int lvl) { - for (int i = 0; i < lvl; i++) { +void set_light_level(int lvl) +{ + for (int i = 0; i < lvl; i++) + { digitalWrite(LIGHT[i], HIGH); } - for (int i = lvl; i < NUM_LIGHTS; i++) { + for (int i = lvl; i < NUM_LIGHTS; i++) + { digitalWrite(LIGHT[i], LOW); } } -void unchanged_anunicateAlarmLevel(Stream *serialport) { +void unchanged_anunicateAlarmLevel(Stream *serialport) +{ unsigned long m = millis(); unsigned long time_in_song = m - start_of_song; unsigned char note = time_in_song / (unsigned long)LEN_OF_NOTE_MS; // serialport->print("note: "); // serialport->println(note); - if (note >= NUM_NOTES) { + if (note >= NUM_NOTES) + { note = 0; start_of_song = m; } unsigned char light_lvl = LIGHT_LEVEL[currentLevel][note]; set_light_level(light_lvl); // TODO: Change this to our device types -//#if !defined(HMWK) +// #if !defined(HMWK) #if defined(GPAD) - if (!currentlyMuted) { + if (!currentlyMuted) + { unsigned char note_lvl = SONGS[currentLevel][note]; // serialport->print("note lvl"); // serialport->println(note_lvl); tone(TONE_PIN, BUZZER_LVL_FREQ_HZ[note_lvl], INF_DURATION); - - } else { + } + else + { noTone(TONE_PIN); } #endif } -void restoreAlarmLevel(Stream *serialport) { - showStatusLCD(currentLevel, currentlyMuted, AlarmMessageBuffer); +void restoreAlarmLevel(Stream *serialport) +{ + showStatusLCD(currentLevel, currentlyMuted, AlarmMessageBuffer); } -void annunciateAlarmLevel(Stream *serialport) { +void annunciateAlarmLevel(Stream *serialport) +{ start_of_song = millis(); unchanged_anunicateAlarmLevel(serialport); showStatusLCD(currentLevel, currentlyMuted, AlarmMessageBuffer); // here is the new call serialport->println("dfPlayer.play"); serialport->println(currentLevel); - if (!currentlyMuted) { + if (!currentlyMuted) + { playNotBusyLevel(currentLevel); } } diff --git a/Firmware/GPAD_API/src/GPAD_menu.h b/Firmware/GPAD_API/src/GPAD_menu.h index f8ff20db..3b93b724 100644 --- a/Firmware/GPAD_API/src/GPAD_menu.h +++ b/Firmware/GPAD_API/src/GPAD_menu.h @@ -1,4 +1,5 @@ - +#ifndef GPAD_MENU_H +#define GPAD_MENU_H void setup_GPAD_menu(); @@ -10,3 +11,5 @@ void registerRotationEvent(bool CW); void registerRotaryEncoderPress(); void reset_menu_navigation(); + +#endif diff --git a/Firmware/GPAD_API/src/InterruptRotator.cpp b/Firmware/GPAD_API/src/InterruptRotator.cpp index a0c96e56..88c989eb 100644 --- a/Firmware/GPAD_API/src/InterruptRotator.cpp +++ b/Firmware/GPAD_API/src/InterruptRotator.cpp @@ -1,16 +1,17 @@ #include "InterruptRotator.h" #include "GPAD_menu.h" -static RotaryEncoder* encoder = nullptr; +static RotaryEncoder *encoder = nullptr; // This global variable represents the state of the menu; -// we are either running the menu (true) or displaying other +// we are either running the menu (true) or displaying other // information (false) extern bool running_menu; -void initRotator() { - // Serial.begin(115200); - // while (!Serial); +void initRotator() +{ + // Serial.begin(115200); + // while (!Serial); Serial.println("InterruptRotator example for the RotaryEncoder library."); encoder = new RotaryEncoder(PIN_IN1, PIN_IN2, RotaryEncoder::LatchMode::TWO03); @@ -19,29 +20,32 @@ void initRotator() { attachInterrupt(digitalPinToInterrupt(PIN_IN2), checkPositionISR, CHANGE); } -void updateRotator() { +void updateRotator() +{ static int pos = 0; encoder->tick(); int newPos = encoder->getPosition(); - if (pos != newPos) { - + if (pos != newPos) + { Serial.print("pos: "); Serial.print(newPos); Serial.print(" dir: "); // If we have rotated the encoder, then we enter the menu... if (!running_menu) - reset_menu_navigation(); + reset_menu_navigation(); int d = (int)(encoder->getDirection()); - // Serial.println(d); + // Serial.println(d); - // int d = (int)(encoder->getDirection()); + // int d = (int)(encoder->getDirection()); bool CW; - if (d == (int) RotaryEncoder::Direction::CLOCKWISE) CW = true; - else CW = false; + if (d == (int)RotaryEncoder::Direction::CLOCKWISE) + CW = true; + else + CW = false; // Serial.print("d : "); // Serial.println(d); // Serial.println((int) RotaryEncoder::Direction::CLOCKWISE); @@ -52,8 +56,10 @@ void updateRotator() { } } -void IRAM_ATTR checkPositionISR() { - if (encoder != nullptr) { +void IRAM_ATTR checkPositionISR() +{ + if (encoder != nullptr) + { encoder->tick(); } } diff --git a/Firmware/GPAD_API/src/InterruptRotator.h b/Firmware/GPAD_API/src/InterruptRotator.h index 3823bdd1..a092c7d7 100644 --- a/Firmware/GPAD_API/src/InterruptRotator.h +++ b/Firmware/GPAD_API/src/InterruptRotator.h @@ -1,15 +1,14 @@ #ifndef INTERRUPT_ROTATOR_H #define INTERRUPT_ROTATOR_H -//#include +// #include #include - // GPIO definitions for ESP32 #if defined(ESP32) -constexpr int CLK = 36; // Rotary encoder CLK pin -constexpr int DT = 39; // Rotary encoder DT pin -constexpr int SW = 34; // Rotary encoder Switch pin +constexpr int CLK = 36; // Rotary encoder CLK pin +constexpr int DT = 39; // Rotary encoder DT pin +constexpr int SW = 34; // Rotary encoder Switch pin #define PIN_IN1 CLK #define PIN_IN2 DT #endif @@ -19,6 +18,4 @@ void initRotator(); void updateRotator(); void IRAM_ATTR checkPositionISR(); - - #endif // INTERRUPT_ROTATOR_H diff --git a/Firmware/GPAD_API/src/RickmanLiquidCrystal_I2C.h b/Firmware/GPAD_API/src/RickmanLiquidCrystal_I2C.h index d22f9c03..dc382580 100644 --- a/Firmware/GPAD_API/src/RickmanLiquidCrystal_I2C.h +++ b/Firmware/GPAD_API/src/RickmanLiquidCrystal_I2C.h @@ -1,51 +1,58 @@ /* -*- C++ -*- */ -// Note: this file copied and slightly modified from +// Note: this file copied and slightly modified from #ifndef RSITE_ARDUINO_MENU_RICKMAN_OUT - #define RSITE_ARDUINO_MENU_RICKMAN_OUT +#define RSITE_ARDUINO_MENU_RICKMAN_OUT - // #ifndef ARDUINO_SAM_DUE - #include +// #ifndef ARDUINO_SAM_DUE +#include - #include +#include // #include - #include - - namespace Menu { - - class lcdOut:public cursorOut { - public: - LiquidCrystal_I2C* device; - inline lcdOut(LiquidCrystal_I2C* o,idx_t *t,panelsList &p,menuOut::styles s=menuOut::minimalRedraw) - :cursorOut(t,p,s),device(o) {} - size_t write(uint8_t ch) override {return device->write(ch);} - void clear() override { - device->clear(); - panels.reset(); - } - void setCursor(idx_t x,idx_t y,idx_t panelNr=0) override { - const panel p=panels[panelNr]; - device->setCursor(p.x+x,p.y+y); - } - idx_t startCursor(navRoot& root,idx_t x,idx_t y,bool charEdit,idx_t panelNr=0) override {return 0;} - idx_t endCursor(navRoot& root,idx_t x,idx_t y,bool charEdit,idx_t panelNr=0) override {return 0;} - idx_t editCursor(navRoot& root,idx_t x,idx_t y,bool editing,bool charEdit,idx_t panelNr=0) override { - trace(MENU_DEBUG_OUT<<"lcdOut::editCursor "<noBlink(); - device->noCursor(); - if (editing) { - device->setCursor(x, y); - if (charEdit) device->cursor(); - else device->blink(); - } - return 0; - } - - }; - - }//namespace Menu - - #endif +#include + +namespace Menu +{ + + class lcdOut : public cursorOut + { + public: + LiquidCrystal_I2C *device; + inline lcdOut(LiquidCrystal_I2C *o, idx_t *t, panelsList &p, menuOut::styles s = menuOut::minimalRedraw) + : cursorOut(t, p, s), device(o) {} + size_t write(uint8_t ch) override { return device->write(ch); } + void clear() override + { + device->clear(); + panels.reset(); + } + void setCursor(idx_t x, idx_t y, idx_t panelNr = 0) override + { + const panel p = panels[panelNr]; + device->setCursor(p.x + x, p.y + y); + } + idx_t startCursor(navRoot &root, idx_t x, idx_t y, bool charEdit, idx_t panelNr = 0) override { return 0; } + idx_t endCursor(navRoot &root, idx_t x, idx_t y, bool charEdit, idx_t panelNr = 0) override { return 0; } + idx_t editCursor(navRoot &root, idx_t x, idx_t y, bool editing, bool charEdit, idx_t panelNr = 0) override + { + trace(MENU_DEBUG_OUT << "lcdOut::editCursor " << x << "," << y << endl); + // text editor cursor + device->noBlink(); + device->noCursor(); + if (editing) + { + device->setCursor(x, y); + if (charEdit) + device->cursor(); + else + device->blink(); + } + return 0; + } + }; + +} // namespace Menu + +#endif // #endif \ No newline at end of file diff --git a/Firmware/GPAD_API/src/WiFiManagerOTA.cpp b/Firmware/GPAD_API/src/WiFiManagerOTA.cpp index 6b024443..97315851 100644 --- a/Firmware/GPAD_API/src/WiFiManagerOTA.cpp +++ b/Firmware/GPAD_API/src/WiFiManagerOTA.cpp @@ -1,27 +1,33 @@ #include "WiFiManagerOTA.h" #include -const char* default_ssid = "ESP32-Setup"; // Default AP Name +const char *default_ssid = "ESP32-Setup"; // Default AP Name String ssid_wf = ""; String password_wf = ""; String ledState = ""; -int WiFiLed = 2; // Modify based on actual LED pin +int WiFiLed = 2; // Modify based on actual LED pin -void saveCredentials(const char* ssid, const char* password) { +void saveCredentials(const char *ssid, const char *password) +{ File file = LittleFS.open("/wifi.txt", "w"); - if (file) { + if (file) + { file.println(ssid); file.println(password); file.close(); Serial.println("WiFi credentials saved."); - } else { + } + else + { Serial.println("Failed to save WiFi credentials."); } } -bool loadCredentials() { +bool loadCredentials() +{ File file = LittleFS.open("/wifi.txt", "r"); - if (!file) { + if (!file) + { Serial.println("No saved WiFi credentials found."); return false; } @@ -36,11 +42,14 @@ bool loadCredentials() { return true; } -void WiFiMan() { +void WiFiMan() +{ WiFiManager wifiManager; - if (!loadCredentials()) { - if (!wifiManager.autoConnect(default_ssid)) { + if (!loadCredentials()) + { + if (!wifiManager.autoConnect(default_ssid)) + { Serial.println("Failed to connect. Restarting..."); ESP.restart(); } @@ -52,32 +61,43 @@ void WiFiMan() { Serial.println("Connected to WiFi!"); } -void initLittleFS() { - if (!LittleFS.begin(true)) { +void initLittleFS() +{ + if (!LittleFS.begin(true)) + { Serial.println("An error occurred while mounting LittleFS."); - } else { - #if (DEBUG >1) + } + else + { +#if (DEBUG > 1) Serial.println("LittleFS mounted successfully."); - #endif +#endif } } -void initWiFi() { +void initWiFi() +{ WiFi.mode(WIFI_STA); WiFi.begin(ssid_wf.c_str(), password_wf.c_str()); Serial.print("Connecting to WiFi .."); - while (WiFi.status() != WL_CONNECTED) { + while (WiFi.status() != WL_CONNECTED) + { Serial.print('.'); delay(1000); } Serial.println("\nConnected. IP Address: " + WiFi.localIP().toString()); } -String processor(const String& var) { - if (var == "STATE") { - if (digitalRead(WiFiLed)) { +String processor(const String &var) +{ + if (var == "STATE") + { + if (digitalRead(WiFiLed)) + { ledState = "ON"; - } else { + } + else + { ledState = "OFF"; } return ledState; diff --git a/Firmware/GPAD_API/src/WiFiManagerOTA.h b/Firmware/GPAD_API/src/WiFiManagerOTA.h index 96a7cb99..2fc09723 100644 --- a/Firmware/GPAD_API/src/WiFiManagerOTA.h +++ b/Firmware/GPAD_API/src/WiFiManagerOTA.h @@ -1,23 +1,23 @@ #ifndef WIFI_MANAGER_H #define WIFI_MANAGER_H -//#include +// #include #include #include #include #include -extern const char* default_ssid; +extern const char *default_ssid; // extern String ssid; // extern String password; extern String ledState; extern int WiFiLed; -void saveCredentials(const char* ssid, const char* password); +void saveCredentials(const char *ssid, const char *password); bool loadCredentials(); void WiFiMan(); void initLittleFS(); void initWiFi(); -String processor(const String& var); +String processor(const String &var); -#endif // WIFI_MANAGER_H +#endif // WIFI_MANAGER_H diff --git a/Firmware/GPAD_API/src/Wink.cpp b/Firmware/GPAD_API/src/Wink.cpp index 3241c55c..85b7433d 100644 --- a/Firmware/GPAD_API/src/Wink.cpp +++ b/Firmware/GPAD_API/src/Wink.cpp @@ -3,32 +3,34 @@ // Date: 20241013 // LICENSE "GNU Affero General Public License, version 3 " - - // Heart beat aka activity indicator LED. -//Set LED for Uno or ESP32 Dev Kit on board blue LED. -#include "Arduino.h" +// Set LED for Uno or ESP32 Dev Kit on board blue LED. +#include - -//Wink the LED -void wink(void) { +// Wink the LED +void wink(void) +{ // TODO - const int LED_BUILTIN = 13; //ESP32 Kit//const int LED_BUILTIN = 2; HWK2 // Not really needed for Arduino UNO it is defined in library + const int LED_BUILTIN = 13; // ESP32 Kit//const int LED_BUILTIN = 2; HWK2 // Not really needed for Arduino UNO it is defined in library pinMode(LED_BUILTIN, OUTPUT); // const int HIGH_TIME_LED = 900; // const int LOW_TIME_LED = 100; const int HIGH_TIME_LED = 1400; const int LOW_TIME_LED = 500; static unsigned long lastLEDtime = 0; - static unsigned long nextLEDchange = 500; //time in ms. - if (((millis() - lastLEDtime) > nextLEDchange) || (millis() < lastLEDtime)) { - if (digitalRead(LED_BUILTIN) == LOW) { - digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level) + static unsigned long nextLEDchange = 500; // time in ms. + if (((millis() - lastLEDtime) > nextLEDchange) || (millis() < lastLEDtime)) + { + if (digitalRead(LED_BUILTIN) == LOW) + { + digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level) nextLEDchange = HIGH_TIME_LED; - } else { - digitalWrite(LED_BUILTIN, LOW); // turn the LED on (HIGH is the voltage level) + } + else + { + digitalWrite(LED_BUILTIN, LOW); // turn the LED on (HIGH is the voltage level) nextLEDchange = LOW_TIME_LED; } lastLEDtime = millis(); } -} //end LED wink +} // end LED wink diff --git a/Firmware/GPAD_API/src/Wink.h b/Firmware/GPAD_API/src/Wink.h index c50fb79b..3cd1b025 100644 --- a/Firmware/GPAD_API/src/Wink.h +++ b/Firmware/GPAD_API/src/Wink.h @@ -1,4 +1,6 @@ - - +#ifndef WINK_H +#define WINK_H void wink(void); + +#endif diff --git a/Firmware/GPAD_API/src/alarm_api.cpp b/Firmware/GPAD_API/src/alarm_api.cpp index 855f0510..5ac2c27a 100644 --- a/Firmware/GPAD_API/src/alarm_api.cpp +++ b/Firmware/GPAD_API/src/alarm_api.cpp @@ -20,7 +20,6 @@ #include "alarm_api.h" #include "gpad_utility.h" - // here is the abstract "state" of the machine, // completely independent of hardware. // This is very simple version of what is probably needed. @@ -31,17 +30,20 @@ AlarmLevel currentLevel = silent; bool currentlyMuted = false; char AlarmMessageBuffer[MAX_BUFFER_SIZE]; -const char *AlarmNames[] = { "OK ", "INFO.", "PROB.", "WARN ", "CRIT.", "PANIC" }; +const char *AlarmNames[] = {"OK ", "INFO.", "PROB.", "WARN ", "CRIT.", "PANIC"}; // This is the abstract alarm function. It CANNOT // assume the msg buffer will exist after this call. // str must be null-terminated string! // It returns the PREVIOUS ALARM LEVEL -int alarm_event(AlarmEvent &event, Stream *serialport) { +int alarm_event(AlarmEvent &event, Stream *serialport) +{ return alarm((AlarmLevel)event.lvl, event.msg, serialport); } -int alarm(AlarmLevel level, char *str, Stream *serialport) { - if (!(level >= 0 && level < NUM_LEVELS)) { +int alarm(AlarmLevel level, char *str, Stream *serialport) +{ + if (!(level >= 0 && level < NUM_LEVELS)) + { serialport->println(F("Bad Level!")); printError(serialport); return -1; @@ -54,11 +56,13 @@ int alarm(AlarmLevel level, char *str, Stream *serialport) { return previousLevel; } -AlarmLevel getCurrentAlarmLevel() { +AlarmLevel getCurrentAlarmLevel() +{ return currentLevel; } -char *getCurrentMessage() { +char *getCurrentMessage() +{ return AlarmMessageBuffer; } diff --git a/Firmware/GPAD_API/src/alarm_api.h b/Firmware/GPAD_API/src/alarm_api.h index 53784bc2..83d8deb2 100644 --- a/Firmware/GPAD_API/src/alarm_api.h +++ b/Firmware/GPAD_API/src/alarm_api.h @@ -22,18 +22,22 @@ #define ALARM_API #include -enum AlarmLevel { silent, - informational, - problem, - warning, - critical, - panic }; +enum AlarmLevel +{ + silent, + informational, + problem, + warning, + critical, + panic +}; // const char *AlarmNames[] = { "OK ","INFO.","PROB.","WARN ","CRIT.","PANIC" }; const int NUM_LEVELS = 6; const int MAX_MSG_LEN = 80; const int MAX_BUFFER_SIZE = MAX_MSG_LEN + 1; -typedef struct { +typedef struct +{ uint8_t lvl; // we will use a null-terminated string! char msg[MAX_MSG_LEN + 1]; diff --git a/Firmware/GPAD_API/src/gpad_serial.cpp b/Firmware/GPAD_API/src/gpad_serial.cpp index bb014751..ad974d14 100644 --- a/Firmware/GPAD_API/src/gpad_serial.cpp +++ b/Firmware/GPAD_API/src/gpad_serial.cpp @@ -22,12 +22,10 @@ #include "gpad_utility.h" #include "alarm_api.h" #include "GPAD_HAL.h" -//#include +// #include extern bool currentlyMuted; - - // We accept maessages up to 128 characters, with 2 characters in front, // and an end-of-string delimiter makes 131 characters! const int COMMAND_BUFFER_SIZE = 131; @@ -41,14 +39,16 @@ CD\n where C is an character, and D is a single digit. */ -// Note: The buffer "buf" used here might be more safely made +// Note: The buffer "buf" used here might be more safely made // a parameter passed in from the caller. -void processSerial(Stream *debugPort, Stream *inputPort, PubSubClient *client) { +void processSerial(Stream *debugPort, Stream *inputPort, PubSubClient *client) +{ // Now see if we have a serial command int rlen; // TODO: This code can probably hang; it needs to have // timeouts added! - if (inputPort->available() > 0) { + if (inputPort->available() > 0) + { // TODO: MAKE NON-BLOCKING // read the incoming bytes: int rlen = inputPort->readBytesUntil('\n', buf, COMMAND_BUFFER_SIZE); @@ -64,8 +64,8 @@ void processSerial(Stream *debugPort, Stream *inputPort, PubSubClient *client) { // Now "light and scream"appropriately... // This does not work on HMWK2 device annunciateAlarmLevel(debugPort); -// removing in an attempt to make faster; reason for adding unknown - rlr -// delay(3000); + // removing in an attempt to make faster; reason for adding unknown - rlr + // delay(3000); printAlarmState(debugPort); } } diff --git a/Firmware/GPAD_API/src/gpad_serial.h b/Firmware/GPAD_API/src/gpad_serial.h index d6f00751..a0faa117 100644 --- a/Firmware/GPAD_API/src/gpad_serial.h +++ b/Firmware/GPAD_API/src/gpad_serial.h @@ -21,10 +21,8 @@ #ifndef GPAD_SERIAL #define GPAD_SERIAL 1 #include -#include - - -void processSerial(Stream *debugPort,Stream *inputPort, PubSubClient *client); +#include +void processSerial(Stream *debugPort, Stream *inputPort, PubSubClient *client); #endif diff --git a/Firmware/GPAD_API/src/gpad_utility.cpp b/Firmware/GPAD_API/src/gpad_utility.cpp index 652db2dd..ca6ecd46 100644 --- a/Firmware/GPAD_API/src/gpad_utility.cpp +++ b/Firmware/GPAD_API/src/gpad_utility.cpp @@ -25,22 +25,27 @@ extern AlarmLevel currentLevel; extern bool currentlyMuted; extern char AlarmMessageBuffer[81]; - -void printError(Stream *serialport) { +void printError(Stream *serialport) +{ serialport->println(F("bad format of command!")); printInstructions(serialport); } -void printInstructions(Stream *serialport) { +void printInstructions(Stream *serialport) +{ serialport->println(F("PubInv GPAD: enter command in form CDa (C is a char, D is a digit)")); } -void printAlarmState(Stream *serialport) { +void printAlarmState(Stream *serialport) +{ serialport->print(F("Muted: ")); serialport->println(currentlyMuted ? "YES" : "NO"); serialport->print(F("LVL: ")); serialport->println(currentLevel); - if (strlen(AlarmMessageBuffer) == 0) { + if (strlen(AlarmMessageBuffer) == 0) + { serialport->println(F("No Message.")); - } else { + } + else + { serialport->print(F("Msg: ")); serialport->println(AlarmMessageBuffer); } diff --git a/Firmware/GPAD_API/src/gpad_utility.h b/Firmware/GPAD_API/src/gpad_utility.h index bd4e68fc..8cd6fcec 100644 --- a/Firmware/GPAD_API/src/gpad_utility.h +++ b/Firmware/GPAD_API/src/gpad_utility.h @@ -22,25 +22,25 @@ #define GPAD_UTILITY 1 #include #ifndef COMPANY_NAME - #define COMPANY_NAME "" +#define COMPANY_NAME "" #endif #ifndef PROG_NAME - #define PROG_NAME "" +#define PROG_NAME "" #endif #ifndef FIRMWARE_VERSION - #define FIRMWARE_VERSION "" +#define FIRMWARE_VERSION "" #endif -//#define HARDWARE_VERSION "V0.0.1 " +// #define HARDWARE_VERSION "V0.0.1 " #ifndef MODEL_NAME - #define MODEL_NAME "" +#define MODEL_NAME "" #endif #ifndef LICENSE - #define LICENSE "GNU Affero General Public License, version 3 " +#define LICENSE "GNU Affero General Public License, version 3 " #endif #ifndef ORIGIN - #define ORIGIN "" +#define ORIGIN "" #endif -#define DEVICE_UNDER_TEST "Krake: DFPlayer" //This is GPAD code, but if it is used in testing... +#define DEVICE_UNDER_TEST "Krake: DFPlayer" // This is GPAD code, but if it is used in testing... // THIS IS FOR DEBUGGING #define LIMIT_POWER_DRAW 1 From e42b83bc2eb5863eb5f3498a04fb0e46b9703f8a Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Sun, 16 Nov 2025 17:49:14 -0500 Subject: [PATCH 13/21] (#273): Updating the README - Changes include linking to instructions for installing the PIO CLI tools and setting up the shell commands - Instructions for building the LittleFS filesystem --- Firmware/GPAD_API/README.md | 35 +++++++++++++++++++++++++++++------ Firmware/GPAD_API/makefile | 3 +++ 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/Firmware/GPAD_API/README.md b/Firmware/GPAD_API/README.md index 4c42ba52..6695e6f9 100644 --- a/Firmware/GPAD_API/README.md +++ b/Firmware/GPAD_API/README.md @@ -17,6 +17,15 @@ Some users prefer not to use VSCode (those who prefer Emacs, Vim, subtext, etc.) +### PlatformIO Core (CLI) Installation +The official [documentation](https://docs.platformio.org/en/latest/core/installation/shell-commands.html#piocore-install-shell-commands) +has great guide on how to install the CLI tooling. [Here](https://docs.platformio.org/en/latest/core/userguide/index.html#piocore-userguide) +is PlatformIO's guide on how to use the CLI command `pio`. The full guide for PlatformIO Core installation is available [here](https://docs.platformio.org/en/latest/core/installation/index.html). + +As the documentation says, you **do not** have to follow all steps in the CLI guide if you have **also** installed the VS Code extension, PlatformIO IDE. It will be advised to follow the directions under the documentation for "Install Shell Commands" to be able to run the commands `pio` and `piodebuggdb` anywhere in the terminal. For the `Makefile` +mentioned below, it is required to install the shell commands for the `make` command to function correctly. + +### Build In the this directory, there is a "make" file. If you have make installed, you can run "make". There are two targets: 1. run --- this does a compile and upload, and begins running a "monitor", which prints the output of the serial monitor and allows commands to be typed in, just as they are typically done in the Arduino IDE. @@ -29,9 +38,23 @@ These commands are implemented on the command line as: make monitor ``` -Remember, with our current hardware, to prepare the Krake to have firmware uploaded, you need to perform these actions: -1. Connect Krake to power and to the computer -2. Press and hold the BOOT button. -3. While still holding BOOT, press and release the RESET button once. -4. Release the BOOT button. -5. The chip is now in boot mode. You can run your flasher and the port should respond. +# Building LittleFS Filesystem +With PlatformIO, the creation of the `LittleFS` is a separate step from building the firmware image. However, it only has to be built if +there have been changes to the `/data` directory and it only has to be uploaded to the device if the the image has changed or the flash +pages containing the file system have been erased. + +## PlatformIO IDE (VS Code Extension) +In the extension side panel, below the `General` section with the `Build` and `Upload` targets, there is another section, `Platform`. Under +the `Platform` section, there are the `Build Filesystem Image` and `Upload Filesystem Image`. Using the `Upload Filesystem Image` target will +build and upload the file system if the file system needs building. + +## PlatformIO Core (CLI) +The full command is `pio run --target uploadfs` but the `Make` target `make uploadfs` can be used. + +# Krake Installation +Installing/flashing a new firmware image requires the device, Krake, to be set into a state for it to allow a new firmware image. That can be accomplished with the following steps: +1. Connect Krake to power and to the computer +2. Press and hold the BOOT button. +3. While still holding BOOT, press and release the RESET button once. +4. Release the BOOT button. +5. The chip is now in boot mode. You can run your flasher and the port should respond. diff --git a/Firmware/GPAD_API/makefile b/Firmware/GPAD_API/makefile index cfa6a6f7..75f7ff91 100644 --- a/Firmware/GPAD_API/makefile +++ b/Firmware/GPAD_API/makefile @@ -21,3 +21,6 @@ run: monitor: pio device monitor -b 115200 + +uploadfs: + pio run --target uploadfs From e8067156ebf2be4d9537e429bde84913929667ae Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Sun, 16 Nov 2025 18:31:44 -0500 Subject: [PATCH 14/21] (#273): Changed `src` dir to `GPAD_API` dir - The project can now be openned in the Arduino IDE by opening the GPAD_API.ino file --- Firmware/GPAD_API/{src => GPAD_API}/DFPlayer.cpp | 0 Firmware/GPAD_API/{src => GPAD_API}/DFPlayer.h | 0 Firmware/GPAD_API/{src => GPAD_API}/GPAD_API.ino | 0 Firmware/GPAD_API/{src => GPAD_API}/GPAD_HAL.cpp | 0 Firmware/GPAD_API/{src => GPAD_API}/GPAD_HAL.h | 0 Firmware/GPAD_API/{src => GPAD_API}/GPAD_menu.cpp | 0 Firmware/GPAD_API/{src => GPAD_API}/GPAD_menu.h | 0 Firmware/GPAD_API/{src => GPAD_API}/InterruptRotator.cpp | 0 Firmware/GPAD_API/{src => GPAD_API}/InterruptRotator.h | 0 Firmware/GPAD_API/{src => GPAD_API}/README.md | 0 Firmware/GPAD_API/{src => GPAD_API}/RickmanLiquidCrystal_I2C.h | 0 Firmware/GPAD_API/{src => GPAD_API}/WiFiManagerOTA.cpp | 0 Firmware/GPAD_API/{src => GPAD_API}/WiFiManagerOTA.h | 0 Firmware/GPAD_API/{src => GPAD_API}/Wink.cpp | 0 Firmware/GPAD_API/{src => GPAD_API}/Wink.h | 0 Firmware/GPAD_API/{src => GPAD_API}/alarm_api.cpp | 0 Firmware/GPAD_API/{src => GPAD_API}/alarm_api.h | 0 Firmware/GPAD_API/{src => GPAD_API}/gpad_serial.cpp | 0 Firmware/GPAD_API/{src => GPAD_API}/gpad_serial.h | 0 Firmware/GPAD_API/{src => GPAD_API}/gpad_utility.cpp | 0 Firmware/GPAD_API/{src => GPAD_API}/gpad_utility.h | 0 Firmware/GPAD_API/platformio.ini | 3 +++ 22 files changed, 3 insertions(+) rename Firmware/GPAD_API/{src => GPAD_API}/DFPlayer.cpp (100%) rename Firmware/GPAD_API/{src => GPAD_API}/DFPlayer.h (100%) rename Firmware/GPAD_API/{src => GPAD_API}/GPAD_API.ino (100%) rename Firmware/GPAD_API/{src => GPAD_API}/GPAD_HAL.cpp (100%) rename Firmware/GPAD_API/{src => GPAD_API}/GPAD_HAL.h (100%) rename Firmware/GPAD_API/{src => GPAD_API}/GPAD_menu.cpp (100%) rename Firmware/GPAD_API/{src => GPAD_API}/GPAD_menu.h (100%) rename Firmware/GPAD_API/{src => GPAD_API}/InterruptRotator.cpp (100%) rename Firmware/GPAD_API/{src => GPAD_API}/InterruptRotator.h (100%) rename Firmware/GPAD_API/{src => GPAD_API}/README.md (100%) rename Firmware/GPAD_API/{src => GPAD_API}/RickmanLiquidCrystal_I2C.h (100%) rename Firmware/GPAD_API/{src => GPAD_API}/WiFiManagerOTA.cpp (100%) rename Firmware/GPAD_API/{src => GPAD_API}/WiFiManagerOTA.h (100%) rename Firmware/GPAD_API/{src => GPAD_API}/Wink.cpp (100%) rename Firmware/GPAD_API/{src => GPAD_API}/Wink.h (100%) rename Firmware/GPAD_API/{src => GPAD_API}/alarm_api.cpp (100%) rename Firmware/GPAD_API/{src => GPAD_API}/alarm_api.h (100%) rename Firmware/GPAD_API/{src => GPAD_API}/gpad_serial.cpp (100%) rename Firmware/GPAD_API/{src => GPAD_API}/gpad_serial.h (100%) rename Firmware/GPAD_API/{src => GPAD_API}/gpad_utility.cpp (100%) rename Firmware/GPAD_API/{src => GPAD_API}/gpad_utility.h (100%) diff --git a/Firmware/GPAD_API/src/DFPlayer.cpp b/Firmware/GPAD_API/GPAD_API/DFPlayer.cpp similarity index 100% rename from Firmware/GPAD_API/src/DFPlayer.cpp rename to Firmware/GPAD_API/GPAD_API/DFPlayer.cpp diff --git a/Firmware/GPAD_API/src/DFPlayer.h b/Firmware/GPAD_API/GPAD_API/DFPlayer.h similarity index 100% rename from Firmware/GPAD_API/src/DFPlayer.h rename to Firmware/GPAD_API/GPAD_API/DFPlayer.h diff --git a/Firmware/GPAD_API/src/GPAD_API.ino b/Firmware/GPAD_API/GPAD_API/GPAD_API.ino similarity index 100% rename from Firmware/GPAD_API/src/GPAD_API.ino rename to Firmware/GPAD_API/GPAD_API/GPAD_API.ino diff --git a/Firmware/GPAD_API/src/GPAD_HAL.cpp b/Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp similarity index 100% rename from Firmware/GPAD_API/src/GPAD_HAL.cpp rename to Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp diff --git a/Firmware/GPAD_API/src/GPAD_HAL.h b/Firmware/GPAD_API/GPAD_API/GPAD_HAL.h similarity index 100% rename from Firmware/GPAD_API/src/GPAD_HAL.h rename to Firmware/GPAD_API/GPAD_API/GPAD_HAL.h diff --git a/Firmware/GPAD_API/src/GPAD_menu.cpp b/Firmware/GPAD_API/GPAD_API/GPAD_menu.cpp similarity index 100% rename from Firmware/GPAD_API/src/GPAD_menu.cpp rename to Firmware/GPAD_API/GPAD_API/GPAD_menu.cpp diff --git a/Firmware/GPAD_API/src/GPAD_menu.h b/Firmware/GPAD_API/GPAD_API/GPAD_menu.h similarity index 100% rename from Firmware/GPAD_API/src/GPAD_menu.h rename to Firmware/GPAD_API/GPAD_API/GPAD_menu.h diff --git a/Firmware/GPAD_API/src/InterruptRotator.cpp b/Firmware/GPAD_API/GPAD_API/InterruptRotator.cpp similarity index 100% rename from Firmware/GPAD_API/src/InterruptRotator.cpp rename to Firmware/GPAD_API/GPAD_API/InterruptRotator.cpp diff --git a/Firmware/GPAD_API/src/InterruptRotator.h b/Firmware/GPAD_API/GPAD_API/InterruptRotator.h similarity index 100% rename from Firmware/GPAD_API/src/InterruptRotator.h rename to Firmware/GPAD_API/GPAD_API/InterruptRotator.h diff --git a/Firmware/GPAD_API/src/README.md b/Firmware/GPAD_API/GPAD_API/README.md similarity index 100% rename from Firmware/GPAD_API/src/README.md rename to Firmware/GPAD_API/GPAD_API/README.md diff --git a/Firmware/GPAD_API/src/RickmanLiquidCrystal_I2C.h b/Firmware/GPAD_API/GPAD_API/RickmanLiquidCrystal_I2C.h similarity index 100% rename from Firmware/GPAD_API/src/RickmanLiquidCrystal_I2C.h rename to Firmware/GPAD_API/GPAD_API/RickmanLiquidCrystal_I2C.h diff --git a/Firmware/GPAD_API/src/WiFiManagerOTA.cpp b/Firmware/GPAD_API/GPAD_API/WiFiManagerOTA.cpp similarity index 100% rename from Firmware/GPAD_API/src/WiFiManagerOTA.cpp rename to Firmware/GPAD_API/GPAD_API/WiFiManagerOTA.cpp diff --git a/Firmware/GPAD_API/src/WiFiManagerOTA.h b/Firmware/GPAD_API/GPAD_API/WiFiManagerOTA.h similarity index 100% rename from Firmware/GPAD_API/src/WiFiManagerOTA.h rename to Firmware/GPAD_API/GPAD_API/WiFiManagerOTA.h diff --git a/Firmware/GPAD_API/src/Wink.cpp b/Firmware/GPAD_API/GPAD_API/Wink.cpp similarity index 100% rename from Firmware/GPAD_API/src/Wink.cpp rename to Firmware/GPAD_API/GPAD_API/Wink.cpp diff --git a/Firmware/GPAD_API/src/Wink.h b/Firmware/GPAD_API/GPAD_API/Wink.h similarity index 100% rename from Firmware/GPAD_API/src/Wink.h rename to Firmware/GPAD_API/GPAD_API/Wink.h diff --git a/Firmware/GPAD_API/src/alarm_api.cpp b/Firmware/GPAD_API/GPAD_API/alarm_api.cpp similarity index 100% rename from Firmware/GPAD_API/src/alarm_api.cpp rename to Firmware/GPAD_API/GPAD_API/alarm_api.cpp diff --git a/Firmware/GPAD_API/src/alarm_api.h b/Firmware/GPAD_API/GPAD_API/alarm_api.h similarity index 100% rename from Firmware/GPAD_API/src/alarm_api.h rename to Firmware/GPAD_API/GPAD_API/alarm_api.h diff --git a/Firmware/GPAD_API/src/gpad_serial.cpp b/Firmware/GPAD_API/GPAD_API/gpad_serial.cpp similarity index 100% rename from Firmware/GPAD_API/src/gpad_serial.cpp rename to Firmware/GPAD_API/GPAD_API/gpad_serial.cpp diff --git a/Firmware/GPAD_API/src/gpad_serial.h b/Firmware/GPAD_API/GPAD_API/gpad_serial.h similarity index 100% rename from Firmware/GPAD_API/src/gpad_serial.h rename to Firmware/GPAD_API/GPAD_API/gpad_serial.h diff --git a/Firmware/GPAD_API/src/gpad_utility.cpp b/Firmware/GPAD_API/GPAD_API/gpad_utility.cpp similarity index 100% rename from Firmware/GPAD_API/src/gpad_utility.cpp rename to Firmware/GPAD_API/GPAD_API/gpad_utility.cpp diff --git a/Firmware/GPAD_API/src/gpad_utility.h b/Firmware/GPAD_API/GPAD_API/gpad_utility.h similarity index 100% rename from Firmware/GPAD_API/src/gpad_utility.h rename to Firmware/GPAD_API/GPAD_API/gpad_utility.h diff --git a/Firmware/GPAD_API/platformio.ini b/Firmware/GPAD_API/platformio.ini index 186aa19f..a5d92643 100644 --- a/Firmware/GPAD_API/platformio.ini +++ b/Firmware/GPAD_API/platformio.ini @@ -8,6 +8,9 @@ ; Please visit documentation for the other options and examples ; https://docs.platformio.org/page/projectconf.html +[platformio] +src_dir = GPAD_API + [env:esp32dev] extra_scripts = pre:pre_extra_script.py From 3fb66a2bb9f37a49e352856dc751212d9ab54036 Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Sun, 16 Nov 2025 20:21:27 -0500 Subject: [PATCH 15/21] (#273): Froze all package versions, included platform version 6.12.0 --- Firmware/GPAD_API/platformio.ini | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Firmware/GPAD_API/platformio.ini b/Firmware/GPAD_API/platformio.ini index a5d92643..3f0fce43 100644 --- a/Firmware/GPAD_API/platformio.ini +++ b/Firmware/GPAD_API/platformio.ini @@ -16,18 +16,18 @@ extra_scripts = pre:pre_extra_script.py build_flags = -DELEGANTOTA_USE_ASYNC_WEBSERVER=1 -platform = espressif32 +platform = espressif32@6.12.0 board = esp32dev board_build.filesystem = littlefs monitor_speed = 115200 framework = arduino lib_deps = - mathertel/RotaryEncoder@^1.5.3 - knolleary/PubSubClient@^2.8 - neu-rah/ArduinoMenu library@^4.21.5 - cygig/DailyStruggleButton@^0.5.1 + mathertel/RotaryEncoder@1.5.3 + knolleary/PubSubClient@2.8 + neu-rah/ArduinoMenu library@4.21.5 + cygig/DailyStruggleButton@0.5.1 neu-rah/streamFlow@0.0.0-alpha+sha.bf16ce8926 - dfrobot/DFRobotDFPlayerMini@^1.0.6 - tzapu/WiFiManager@^2.0.17 - ayushsharma82/ElegantOTA@^3.1.7 - marcoschwartz/LiquidCrystal_I2C@^1.1.4 + dfrobot/DFRobotDFPlayerMini@1.0.6 + tzapu/WiFiManager@2.0.17 + ayushsharma82/ElegantOTA@3.1.7 + marcoschwartz/LiquidCrystal_I2C@1.1.4 From 12e6cb8f51e02917a79061730656ece3ace0126a Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Mon, 17 Nov 2025 09:41:25 -0500 Subject: [PATCH 16/21] (#273): Reverted package versioning to recommend value - PlatformIO recommends listing a specific version for packages (and platforms) and preceding the '@' with a '^' (caret) so the latest compatible version will be used - The "tip" is in a blue box under this section: https://docs.platformio.org/en/latest/core/userguide/pkg/cmd_install.html#id17 --- Firmware/GPAD_API/platformio.ini | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Firmware/GPAD_API/platformio.ini b/Firmware/GPAD_API/platformio.ini index 3f0fce43..9246147c 100644 --- a/Firmware/GPAD_API/platformio.ini +++ b/Firmware/GPAD_API/platformio.ini @@ -16,18 +16,18 @@ extra_scripts = pre:pre_extra_script.py build_flags = -DELEGANTOTA_USE_ASYNC_WEBSERVER=1 -platform = espressif32@6.12.0 +platform = espressif32@^6.12.0 board = esp32dev board_build.filesystem = littlefs monitor_speed = 115200 framework = arduino lib_deps = - mathertel/RotaryEncoder@1.5.3 - knolleary/PubSubClient@2.8 - neu-rah/ArduinoMenu library@4.21.5 - cygig/DailyStruggleButton@0.5.1 + mathertel/RotaryEncoder@^1.5.3 + knolleary/PubSubClient@^2.8 + neu-rah/ArduinoMenu library@^4.21.5 + cygig/DailyStruggleButton@^0.5.1 neu-rah/streamFlow@0.0.0-alpha+sha.bf16ce8926 - dfrobot/DFRobotDFPlayerMini@1.0.6 - tzapu/WiFiManager@2.0.17 - ayushsharma82/ElegantOTA@3.1.7 - marcoschwartz/LiquidCrystal_I2C@1.1.4 + dfrobot/DFRobotDFPlayerMini@^1.0.6 + tzapu/WiFiManager@^2.0.17 + ayushsharma82/ElegantOTA@^3.1.7 + marcoschwartz/LiquidCrystal_I2C@^1.1.4 From ca8c4079b450ceb3bb3551a0c20fa104884332a3 Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Thu, 13 Nov 2025 21:22:21 -0500 Subject: [PATCH 17/21] Feature: #206 - Added `Command` enum - Added a char enum which maps the chars used to indicate the commands to actual enum variants - The main switch statement in GPAD_HAL.cpp now switches over the Command enum instead of the hardcoded chars --- Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp | 16 ++++++++-------- Firmware/GPAD_API/GPAD_API/GPAD_HAL.h | 9 +++++++++ 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp b/Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp index 0de718ac..9501e3be 100644 --- a/Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp +++ b/Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp @@ -424,24 +424,24 @@ void interpretBuffer(char *buf, int rlen, Stream *serialport, PubSubClient *clie printError(serialport); return; } - char C = buf[0]; + Command command = static_cast(buf[0]); serialport->print(F("Command: ")); - serialport->println(C); - switch (C) + serialport->println(F(command)); + switch (command) { - case 's': + case Command::MUTE: serialport->println(F("Muting Case!")); currentlyMuted = true; break; - case 'u': + case Command::UNMUTE: serialport->println(F("UnMuting Case!")); currentlyMuted = false; break; - case 'h': // help + case Command::HELP: // help printInstructions(serialport); break; - case 'a': + case Command::ALARM: { // In the case of an alarm state, the rest of the buffer is a message. // we will read up to 60 characters from this buffer for display on our @@ -462,7 +462,7 @@ void interpretBuffer(char *buf, int rlen, Stream *serialport, PubSubClient *clie break; } - case 'i': // Information. Firmware Version, Mute Status, + case Command::INFO: // Information. Firmware Version, Mute Status, { // Firmware Version // 81+23 = Maximum string length diff --git a/Firmware/GPAD_API/GPAD_API/GPAD_HAL.h b/Firmware/GPAD_API/GPAD_API/GPAD_HAL.h index d8baef2f..0c8c1624 100644 --- a/Firmware/GPAD_API/GPAD_API/GPAD_HAL.h +++ b/Firmware/GPAD_API/GPAD_API/GPAD_HAL.h @@ -122,6 +122,15 @@ extern HardwareSerial uartSerial1; #define UART2_BAUD_RATE 9600 extern HardwareSerial uartSerial1; +enum class Command : char +{ + MUTE = 's', + UNMUTE = 'u', + HELP = 'h', + ALARM = 'a', + INFO = 'i', +}; + // SPI Functions.... void setup_spi(); void receive_byte(byte c); From 0b3f144fd6a50d1c3c42819916ad523803865f25 Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Thu, 13 Nov 2025 22:09:45 -0500 Subject: [PATCH 18/21] Feature: #206 - Defined GPAD_API_VERSION value and publish value - GPAD_API_VERSION is now defined as a preprocessor directive, like FIRMWARE_VERSION - The value is published via MQTT just like the FIRMWARE_VERSION --- Firmware/GPAD_API/GPAD_API/gpad_utility.h | 3 +++ Firmware/GPAD_API/pre_extra_script.py | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Firmware/GPAD_API/GPAD_API/gpad_utility.h b/Firmware/GPAD_API/GPAD_API/gpad_utility.h index 8cd6fcec..29f08826 100644 --- a/Firmware/GPAD_API/GPAD_API/gpad_utility.h +++ b/Firmware/GPAD_API/GPAD_API/gpad_utility.h @@ -30,6 +30,9 @@ #ifndef FIRMWARE_VERSION #define FIRMWARE_VERSION "" #endif +#ifndef GPAD_API_VERSION +#define GPAD_API_VERSION "" +#endif // #define HARDWARE_VERSION "V0.0.1 " #ifndef MODEL_NAME #define MODEL_NAME "" diff --git a/Firmware/GPAD_API/pre_extra_script.py b/Firmware/GPAD_API/pre_extra_script.py index e83baff2..7307eefe 100644 --- a/Firmware/GPAD_API/pre_extra_script.py +++ b/Firmware/GPAD_API/pre_extra_script.py @@ -3,7 +3,8 @@ cpp_defines = [ ("COMPANY_NAME", "PubInv "), # For the Broker ID for MQTT ("PROG_NAME", "GPAD_API "), # This program - ("FIRMWARE_VERSION", "0.46 "), # Initial Menu implementation + ("FIRMWARE_VERSION", "0.45 "), # Initial Menu implementation + ("GPAD_API_VERSION", "1.0.0"), ("MODEL_NAME", "KRAKE_"), ("LICENSE", "GNU Affero General Public License, version 3 "), ("ORIGIN", "US"), From 38a7da99571930ef1ab19967a21efa2394c2c720 Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Sat, 6 Dec 2025 14:56:42 -0500 Subject: [PATCH 19/21] (#206): API Version is stored in class, no longer a compile time argument - The GPAD API version is now hardcoded as an actual value - It is not something that should be able to be changed by a compilation flag --- Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp | 37 ++++++++++++++++++ Firmware/GPAD_API/GPAD_API/GPAD_HAL.h | 46 ++++++++++++++++++----- Firmware/GPAD_API/GPAD_API/gpad_utility.h | 3 -- Firmware/GPAD_API/pre_extra_script.py | 1 - 4 files changed, 74 insertions(+), 13 deletions(-) diff --git a/Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp b/Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp index 9501e3be..9d9f835c 100644 --- a/Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp +++ b/Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp @@ -26,6 +26,10 @@ #include "WiFiManagerOTA.h" #include "GPAD_menu.h" +using namespace gpad_hal; + +GPAD_HAL gpadHal(SemanticVersion(0, 1, 0)); + extern IPAddress myIP; // Use Serial1 for UART communication @@ -474,6 +478,13 @@ void interpretBuffer(char *buf, int rlen, Stream *serialport, PubSubClient *clie strcat(onInfoMsg, FIRMWARE_VERSION); client->publish(publish_Ack_Topic, onInfoMsg); serialport->println(onInfoMsg); + onInfoMsg[0] = '\0'; + + // Report API version + strcat(onInfoMsg, gpadHal.getVersion().toString().c_str()); + client->publish(publish_Ack_Topic, onInfoMsg); + serialport->println(onInfoMsg); + onInfoMsg[0] = '\0'; // Up time onInfoMsg[0] = '\0'; @@ -748,3 +759,29 @@ void annunciateAlarmLevel(Stream *serialport) playNotBusyLevel(currentLevel); } } + +GPAD_HAL::GPAD_HAL(SemanticVersion version) + : version(version) +{ +} + +SemanticVersion &GPAD_HAL::getVersion() +{ + return this->version; +} + +SemanticVersion::SemanticVersion(uint8_t major, uint8_t minor, uint8_t patch) + : major(major), + minor(minor), + patch(patch) +{ +} + +std::string SemanticVersion::toString() +{ + std::string versionString; + + versionString.append("0.0.0"); + + return versionString; +} \ No newline at end of file diff --git a/Firmware/GPAD_API/GPAD_API/GPAD_HAL.h b/Firmware/GPAD_API/GPAD_API/GPAD_HAL.h index 0c8c1624..899cb82a 100644 --- a/Firmware/GPAD_API/GPAD_API/GPAD_HAL.h +++ b/Firmware/GPAD_API/GPAD_API/GPAD_HAL.h @@ -18,8 +18,8 @@ */ -#ifndef GPAD_HAL -#define GPAD_HAL 1 +#ifndef GPAD_HAL_H +#define GPAD_HAL_H #include // #include #include @@ -122,14 +122,42 @@ extern HardwareSerial uartSerial1; #define UART2_BAUD_RATE 9600 extern HardwareSerial uartSerial1; -enum class Command : char +namespace gpad_hal { - MUTE = 's', - UNMUTE = 'u', - HELP = 'h', - ALARM = 'a', - INFO = 'i', -}; + enum class Command : char + { + MUTE = 's', + UNMUTE = 'u', + HELP = 'h', + ALARM = 'a', + INFO = 'i', + }; + + class SemanticVersion + { + public: + SemanticVersion(uint8_t major, uint8_t minor, uint8_t patch); + + std::string toString(); + + private: + uint8_t major; + uint8_t minor; + uint8_t patch; + }; + + class GPAD_HAL + { + public: + GPAD_HAL(SemanticVersion version); + + SemanticVersion &getVersion(); + + private: + SemanticVersion version; + }; + +} // SPI Functions.... void setup_spi(); diff --git a/Firmware/GPAD_API/GPAD_API/gpad_utility.h b/Firmware/GPAD_API/GPAD_API/gpad_utility.h index 29f08826..8cd6fcec 100644 --- a/Firmware/GPAD_API/GPAD_API/gpad_utility.h +++ b/Firmware/GPAD_API/GPAD_API/gpad_utility.h @@ -30,9 +30,6 @@ #ifndef FIRMWARE_VERSION #define FIRMWARE_VERSION "" #endif -#ifndef GPAD_API_VERSION -#define GPAD_API_VERSION "" -#endif // #define HARDWARE_VERSION "V0.0.1 " #ifndef MODEL_NAME #define MODEL_NAME "" diff --git a/Firmware/GPAD_API/pre_extra_script.py b/Firmware/GPAD_API/pre_extra_script.py index 7307eefe..023a37ef 100644 --- a/Firmware/GPAD_API/pre_extra_script.py +++ b/Firmware/GPAD_API/pre_extra_script.py @@ -4,7 +4,6 @@ ("COMPANY_NAME", "PubInv "), # For the Broker ID for MQTT ("PROG_NAME", "GPAD_API "), # This program ("FIRMWARE_VERSION", "0.45 "), # Initial Menu implementation - ("GPAD_API_VERSION", "1.0.0"), ("MODEL_NAME", "KRAKE_"), ("LICENSE", "GNU Affero General Public License, version 3 "), ("ORIGIN", "US"), From 7084f89fa22b87df7b30db091c9c0eb1f9fcdada Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Sun, 7 Dec 2025 18:50:05 -0500 Subject: [PATCH 20/21] (#206): API version is now printed out, leveraged const for methods --- Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp | 19 ++++++++--------- Firmware/GPAD_API/GPAD_API/GPAD_HAL.h | 27 ++++++++++++++++++++----- 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp b/Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp index 9d9f835c..b82ebfb8 100644 --- a/Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp +++ b/Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp @@ -28,8 +28,6 @@ using namespace gpad_hal; -GPAD_HAL gpadHal(SemanticVersion(0, 1, 0)); - extern IPAddress myIP; // Use Serial1 for UART communication @@ -481,7 +479,8 @@ void interpretBuffer(char *buf, int rlen, Stream *serialport, PubSubClient *clie onInfoMsg[0] = '\0'; // Report API version - strcat(onInfoMsg, gpadHal.getVersion().toString().c_str()); + strcat(onInfoMsg, "GPAD API Version: "); + strcat(onInfoMsg, gpadApi.getVersion().toString().c_str()); client->publish(publish_Ack_Topic, onInfoMsg); serialport->println(onInfoMsg); onInfoMsg[0] = '\0'; @@ -760,12 +759,12 @@ void annunciateAlarmLevel(Stream *serialport) } } -GPAD_HAL::GPAD_HAL(SemanticVersion version) +GPAD_API::GPAD_API(SemanticVersion version) : version(version) { } -SemanticVersion &GPAD_HAL::getVersion() +const SemanticVersion &GPAD_API::getVersion() const { return this->version; } @@ -777,11 +776,13 @@ SemanticVersion::SemanticVersion(uint8_t major, uint8_t minor, uint8_t patch) { } -std::string SemanticVersion::toString() +std::string SemanticVersion::toString() const { - std::string versionString; - - versionString.append("0.0.0"); + std::string versionString = std::to_string(this->major); + versionString.push_back('.'); + versionString.append(std::to_string(this->minor)); + versionString.push_back('.'); + versionString.append(std::to_string(this->patch)); return versionString; } \ No newline at end of file diff --git a/Firmware/GPAD_API/GPAD_API/GPAD_HAL.h b/Firmware/GPAD_API/GPAD_API/GPAD_HAL.h index 899cb82a..aba0f8e2 100644 --- a/Firmware/GPAD_API/GPAD_API/GPAD_HAL.h +++ b/Firmware/GPAD_API/GPAD_API/GPAD_HAL.h @@ -124,6 +124,11 @@ extern HardwareSerial uartSerial1; namespace gpad_hal { + + static const uint8_t API_MAJOR_VERSION = 0; + static const uint8_t API_MINOR_VERSION = 1; + static const uint8_t API_PATCH_VERSION = 0; + enum class Command : char { MUTE = 's', @@ -133,12 +138,23 @@ namespace gpad_hal INFO = 'i', }; + /** + * SemanticVersion stores a version following the "semantic versioning" convention + * defined here: https://semver.org/ + * + * In summary: + * - Major version defines breaking an incompatible changes with different versions + * - Minor version adds new functionality in a backwards capability + * ie v2.4.1 and v2.5.1 are still compatible but v2.5.1 may have additional functionality + * - Patch version simply addresses bugs with no new features again in a backwards + * compatible way + */ class SemanticVersion { public: SemanticVersion(uint8_t major, uint8_t minor, uint8_t patch); - std::string toString(); + std::string toString() const; private: uint8_t major; @@ -146,17 +162,18 @@ namespace gpad_hal uint8_t patch; }; - class GPAD_HAL + class GPAD_API { public: - GPAD_HAL(SemanticVersion version); + GPAD_API(SemanticVersion version); - SemanticVersion &getVersion(); + const SemanticVersion &getVersion() const; private: - SemanticVersion version; + const SemanticVersion version; }; + const GPAD_API gpadApi = GPAD_API(SemanticVersion(API_MAJOR_VERSION, API_MINOR_VERSION, API_PATCH_VERSION)); } // SPI Functions.... From a020d88f552656691154a07afce97ce337f48882 Mon Sep 17 00:00:00 2001 From: TheBakedPotato <11617336+TheBakedPotato@users.noreply.github.com> Date: Mon, 8 Dec 2025 09:03:23 -0500 Subject: [PATCH 21/21] (#283): Moving functionality from GPAD_HAL into the GPAD_API class --- Firmware/GPAD_API/GPAD_API/GPAD_API.ino | 2 + Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp | 182 ++++++++++++------------ Firmware/GPAD_API/GPAD_API/GPAD_HAL.h | 7 +- 3 files changed, 100 insertions(+), 91 deletions(-) diff --git a/Firmware/GPAD_API/GPAD_API/GPAD_API.ino b/Firmware/GPAD_API/GPAD_API/GPAD_API.ino index 2d8f2f79..259efe20 100644 --- a/Firmware/GPAD_API/GPAD_API/GPAD_API.ino +++ b/Firmware/GPAD_API/GPAD_API/GPAD_API.ino @@ -426,6 +426,8 @@ void setup() // Setup the SWITCH_ENCODER GPAD_HAL_setup(&Serial); + const gpad_hal::GPAD_API gpadApi = gpad_hal::GPAD_API(&Serial); + #if (DEBUG > 0) Serial.println("MAC: "); Serial.println(macAddressString); diff --git a/Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp b/Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp index b82ebfb8..061fd144 100644 --- a/Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp +++ b/Firmware/GPAD_API/GPAD_API/GPAD_HAL.cpp @@ -233,13 +233,13 @@ void updateFromSPI() // Have to get a serialport here // void myCallback(byte buttonEvent) { -void encoderSwitchCallback(byte buttonEvent) +void GPAD_API::encoderSwitchCallback(byte buttonEvent) const { switch (buttonEvent) { case onPress: // Do something... - local_ptr_to_serial->println(F("ENCODER_SWITCH onPress")); + this->serial->println(F("ENCODER_SWITCH onPress")); // currentlyMuted = !currentlyMuted; // start_of_song = millis(); // annunciateAlarmLevel(local_ptr_to_serial); @@ -249,7 +249,7 @@ void encoderSwitchCallback(byte buttonEvent) break; case onRelease: // Do nothing... - local_ptr_to_serial->println(F("ENCODER_SWITCH onRelease")); + this->serial->println(F("ENCODER_SWITCH onRelease")); break; case onHold: // Do nothing... @@ -281,25 +281,25 @@ void encoderSwitchCallback(byte buttonEvent) // Have to get a serialport here // void myCallback(byte buttonEvent) { -void muteButtonCallback(byte buttonEvent) +void GPAD_API::muteButtonCallback(byte buttonEvent) { switch (buttonEvent) { case onPress: // Do something... - local_ptr_to_serial->println(F("SWITCH_MUTE onPress")); + serial->println(F("SWITCH_MUTE onPress")); currentlyMuted = !currentlyMuted; start_of_song = millis(); - annunciateAlarmLevel(local_ptr_to_serial); - printAlarmState(local_ptr_to_serial); + annunciateAlarmLevel(serial); + printAlarmState(serial); break; case onRelease: // Do nothing... - local_ptr_to_serial->println(F("SWITCH_MUTE onRelease")); + serial->println(F("SWITCH_MUTE onRelease")); break; case onHold: // Do nothing... - local_ptr_to_serial->println(F("SWITCH_MUTE onHold")); + serial->println(F("SWITCH_MUTE onHold")); break; // onLongPress is indidcated when you hold onto the button // more than longPressTime in milliseconds @@ -325,84 +325,6 @@ void muteButtonCallback(byte buttonEvent) } } -void GPAD_HAL_setup(Stream *serialport) -{ - // Setup and present LCD splash screen - // Setup the SWITCH_MUTE - // Setup the SWITCH_ENCODER - // Print instructions on DEBUG serial port - - local_ptr_to_serial = serialport; - Wire.begin(); - lcd.init(); -#if (DEBUG > 0) - serialport->println(F("Clear LCD")); -#endif - clearLCD(); - delay(100); -#if (DEBUG > 0) - serialport->println(F("Start LCD splash")); -#endif - - splashLCD(); - -#if (DEBUG > 0) - serialport->println(F("EndLCD splash")); -#endif - - // Setup GPIO pins, Mute and lights - pinMode(SWITCH_MUTE, INPUT_PULLUP); // The SWITCH_MUTE is different on Atmega vs ESP32. Is this redundant? - pinMode(SWITCH_ENCODER, INPUT_PULLUP); // The SWITCH_ENCODER is new to Krake. Is this redundant? - - for (int i = 0; i < NUM_LIGHTS; i++) - { -#if (DEBUG > 0) - serialport->print(LIGHT[i]); - serialport->print(", "); -#endif - pinMode(LIGHT[i], OUTPUT); - // Rob trying to prevent resets - // This is necessary on SN#3 - digitalWrite(LIGHT[i], LOW); - } - serialport->println(""); - - muteButton.set(SWITCH_MUTE, muteButtonCallback); - muteButton.enableLongPress(longPressTime); - muteButton.enableMultiHit(multiHitTime, multiHitTarget); - - // SW4.set(GPIO_SW4, SendEmergMessage, INT_PULL_UP); - // encoderSwitchButton.set(SWITCH_ENCODER, encoderSwitchCallback, INT_PULL_UP); - encoderSwitchButton.set(SWITCH_ENCODER, encoderSwitchCallback); - encoderSwitchButton.enableLongPress(longPressTime); - encoderSwitchButton.enableMultiHit(multiHitTime, multiHitTarget); - - printInstructions(serialport); - AlarmMessageBuffer[0] = '\0'; - - // digitalWrite(LED_BUILTIN, LOW); // turn the LED off at end of setup - -#if !defined(HMWK) // On Homework2, LCD goes blank early - // Here initialize the UART1 - // FLE the Serial1 is faliing to terminate - // pinMode(RXD1, INPUT_PULLUP); - uartSerial1.begin(UART1_BAUD_RATE, SERIAL_8N1, RXD1, TXD1); // UART setup. On Homework2, LCD goes blank early - uartSerial1.flush(); // Clear any Serial1 crud at reset. - -#if (DEBUG > 0) - serialport->println(F("uartSerial1 Setup")); -#endif -#endif - - // Here initialize the UART2 - pinMode(RXD2, INPUT_PULLUP); - uartSerial2.begin(UART2_BAUD_RATE, SERIAL_8N1, RXD2, TXD2); // UART setup - uartSerial2.flush(); -#if (DEBUG > 0) - serialport->println(F("uartSerial2 Setup")); -#endif -} // end GPAD_HAL_setup() - // This routine should be refactored so that it only "interprets" // the character buffer and returns an "abstract" command to be acted on // elseshere. This will allow us to remove the PubSubClient from the this file, @@ -732,7 +654,7 @@ void unchanged_anunicateAlarmLevel(Stream *serialport) // serialport->print("note lvl"); // serialport->println(note_lvl); - tone(TONE_PIN, BUZZER_LVL_FREQ_HZ[note_lvl], INF_DURATION); + tone(TONE_PIN, BUZZER_LVL_FREQ_HZ[note_lvl], INF_Dt->printlnURATION); } else { @@ -759,9 +681,89 @@ void annunciateAlarmLevel(Stream *serialport) } } -GPAD_API::GPAD_API(SemanticVersion version) - : version(version) +GPAD_API::GPAD_API(Stream *serial) + : version(SemanticVersion(API_MAJOR_VERSION, API_MINOR_VERSION, API_PATCH_VERSION)), + serial(serial) { + + using namespace std::placeholders; + // Setup and present LCD splash screen + // Setup the SWITCH_MUTE + // Setup the SWITCH_ENCODER + // Print instructions on DEBUG serial port + + Wire.begin(); + lcd.init(); +#if (DEBUG > 0) + this->serial->println(F("Clear LCD")); +#endif + clearLCD(); + delay(100); +#if (DEBUG > 0) + this->serial->println(F("Start LCD splash")); +#endif + + splashLCD(); + +#if (DEBUG > 0) + this->serial->println(F("EndLCD splash")); +#endif + + // Setup GPIO pins, Mute and lights + pinMode(SWITCH_MUTE, INPUT_PULLUP); // The SWITCH_MUTE is different on Atmega vs ESP32. Is this redundant? + pinMode(SWITCH_ENCODER, INPUT_PULLUP); // The SWITCH_ENCODER is new to Krake. Is this redundant? + + for (int i = 0; i < NUM_LIGHTS; i++) + { +#if (DEBUG > 0) + this->serial->print(LIGHT[i]); + this->serial->print(", "); +#endif + pinMode(LIGHT[i], OUTPUT); + // Rob trying to prevent resets + // This is necessary on SN#3 + digitalWrite(LIGHT[i], LOW); + } + this->serial->println(""); + + std::function f = std::bind(&GPAD_API::muteButtonCallback, this, _1); + + auto f1 = (void (*)(byte))(&f); + + muteButton.set(SWITCH_MUTE, f1); + muteButton.enableLongPress(longPressTime); + muteButton.enableMultiHit(multiHitTime, multiHitTarget); + + // SW4.set(GPIO_SW4, SendEmergMessage, INT_PULL_UP); + // encoderSwitchButton.set(SWITCH_ENCODER, encoderSwitchCallback, INT_PULL_UP); + // encoderSwitchButton.set(SWITCH_ENCODER, encoderSwitchCallback); + encoderSwitchButton.enableLongPress(longPressTime); + encoderSwitchButton.enableMultiHit(multiHitTime, multiHitTarget); + + printInstructions(this->serial); + AlarmMessageBuffer[0] = '\0'; + + // digitalWrite(LED_BUILTIN, LOW); // turn the LED off at end of setup + +#if !defined(HMWK) // On Homework2, LCD goes blank early + // Here initialize the UART1 + // FLE the Serial1 is faliing to terminate + // pinMode(RXD1, INPUT_PULLUP); + uartSerial1.begin(UART1_BAUD_RATE, SERIAL_8N1, RXD1, TXD1); // UART setup. On Homework2, LCD goes blank early + uartSerial1.flush(); // Clear any Serial1 crud at reset. + +#if (DEBUG > 0) + this->serial->println(F("uartSerial1 Setup")); +#endif +#endif + + // Here initialize the UART2 + pinMode(RXD2, INPUT_PULLUP); + uartSerial2.begin(UART2_BAUD_RATE, SERIAL_8N1, RXD2, TXD2); // UART setup + uartSerial2.flush(); +#if (DEBUG > 0) + this->serial->println(F("uartSerial2 Setup")); +#endif } const SemanticVersion &GPAD_API::getVersion() const diff --git a/Firmware/GPAD_API/GPAD_API/GPAD_HAL.h b/Firmware/GPAD_API/GPAD_API/GPAD_HAL.h index aba0f8e2..0db23147 100644 --- a/Firmware/GPAD_API/GPAD_API/GPAD_HAL.h +++ b/Firmware/GPAD_API/GPAD_API/GPAD_HAL.h @@ -165,12 +165,17 @@ namespace gpad_hal class GPAD_API { public: - GPAD_API(SemanticVersion version); + GPAD_API(Stream *serial); const SemanticVersion &getVersion() const; private: const SemanticVersion version; + Stream *serial; + + void muteButtonCallback(byte buttonEvent); + void encoderSwitchCallback(byte buttonEvent) const; + void showStatusLCD(AlarmLevel level, bool muted, char *msg) const; }; const GPAD_API gpadApi = GPAD_API(SemanticVersion(API_MAJOR_VERSION, API_MINOR_VERSION, API_PATCH_VERSION));