diff --git a/Software/platformio.ini b/Software/platformio.ini index 53c169c..8c11082 100644 --- a/Software/platformio.ini +++ b/Software/platformio.ini @@ -15,12 +15,11 @@ framework = arduino monitor_speed = 115200 lib_deps = knolleary/PubSubClient@^2.8 - thingpulse/ESP8266 and ESP32 OLED driver for SSD1306 displays@^4.3.0 - miguelbalboa/MFRC522@^1.4.10 thijse/ArduinoLog@^1.1.1 uipethernet/UIPEthernet@^2.0.12 bblanchon/ArduinoJson@^6.19.4 mbed-feb11/Crypto@0.0.0+sha.f04410cef037 adafruit/Adafruit PN532@^1.3.3 -build_flags = - -D PN532_I2C_ADDRESS=0x24 \ No newline at end of file + adafruit/Adafruit SSD1306@^2.5.13 +build_flags = + -D PN532_I2C_ADDRESS=0x24 diff --git a/Software/src/Display.cpp b/Software/src/Display.cpp index 552482b..390cd34 100644 --- a/Software/src/Display.cpp +++ b/Software/src/Display.cpp @@ -1,28 +1,49 @@ -#include -#include +#include "Display.h" +#include +#include +#include +// Constructor: initializes I2C, creates the display object, +// initializes the display, clears it, and sets an initial rotation. Display::Display(int sda, int scl, int readerid) { this->readerid = readerid; - display = new SSD1306Wire(0x3c, sda, scl); - display->init(); - display->setTextAlignment(TEXT_ALIGN_CENTER); - display->flipScreenVertically(); + // Initialize I2C with custom SDA and SCL pins. + Wire.begin(sda, scl); + + // Create display object (128x64) using I2C and default I2C address 0x3C. + display = new Adafruit_SSD1306(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); + if (!display->begin(SSD1306_SWITCHCAPVCC, 0x3C)) + { + Serial.println("SSD1306 allocation failed"); + while (1) + { + yield(); // Infinite loop if display initialization fails + } + } + display->clearDisplay(); + + // Flip the display vertically (if needed) + display->setRotation(0); + + // Initialize text buffers. ReaderInfo[0] = '\0'; // Empty string - strcpy(Title, "Boot ..."); // Set initial title + strcpy(Title, "Boot ..."); // Initial title Info[0] = '\0'; // Empty string } void Display::clearReaderInfo() { char buffer[DISPLAY_BUFFER_SIZE]; + // Format the reader id as a 5-digit number. sprintf(buffer, "%05d", readerid); writeReaderInfo(buffer); } void Display::createReaderInfo(const char *state) { + // Ensure there is enough room in the buffer (6 extra chars for the readerid) if (strlen(state) < DISPLAY_BUFFER_SIZE - 1 - 6) { char buffer[DISPLAY_BUFFER_SIZE]; @@ -55,50 +76,71 @@ void Display::writeInfo(const char *text) { strcpy(Info, text); } - updateDisplay(); } +// Helper: Draws the given text centered horizontally at vertical position y. +void Display::drawCenteredText(const char *text, int y) +{ + int16_t x1, y1; + uint16_t w, h; + // Get the bounding box of the text. + display->getTextBounds(text, 0, y, &x1, &y1, &w, &h); + int x = (SCREEN_WIDTH - w) / 2; + display->setCursor(x, y); + display->print(text); +} + void Display::updateDisplay() { - display->clear(); + display->clearDisplay(); - display->setFont(ArialMT_Plain_10); - display->drawString(64, 0, ReaderInfo); + // Draw ReaderInfo (using text size 1) + display->setTextSize(1); + display->setTextColor(SSD1306_WHITE); + drawCenteredText(ReaderInfo, 0); - display->setFont(ArialMT_Plain_24); - display->drawString(64, 13, Title); + // Draw Title (using text size 2 for emphasis) + display->setTextSize(2); + // The y-coordinate is chosen to leave room for the first line. + drawCenteredText(Title, 16); - display->setFont(ArialMT_Plain_16); - display->drawString(64, 40, Info); + // Draw Info (using text size 1) + display->setTextSize(1); + drawCenteredText(Info, 40); display->display(); } void Display::updateByMQTT(const char *topic, byte *payload, unsigned int length) { - char topic_displayTitle[] = "fabreader/00000/display/title"; - sprintf(topic_displayTitle, "fabreader/%05d/display/title", readerid); + // Build expected MQTT topics for title, info, and stopping OTA. + char topic_displayTitle[32]; + snprintf(topic_displayTitle, sizeof(topic_displayTitle), "fabreader/%05d/display/title", readerid); - char topic_displayInfo[] = "fabreader/00000/display/info"; - sprintf(topic_displayInfo, "fabreader/%05d/display/info", readerid); + char topic_displayInfo[32]; + snprintf(topic_displayInfo, sizeof(topic_displayInfo), "fabreader/%05d/display/info", readerid); - char topic_stopOTA[] = "fabreader/00000/stopOTA"; - sprintf(topic_stopOTA, "fabreader/%05d/stopOTA", readerid); + char topic_stopOTA[32]; + snprintf(topic_stopOTA, sizeof(topic_stopOTA), "fabreader/%05d/stopOTA", readerid); + // Copy the payload into a null-terminated string. char *buffer = new char[length + 1]; memcpy(buffer, payload, length); + buffer[length] = '\0'; - if (!strcmp(topic, topic_displayTitle)) + // Update display based on the topic. + if (strcmp(topic, topic_displayTitle) == 0) { writeTitle(buffer); } - else if (!strcmp(topic, topic_displayInfo)) + else if (strcmp(topic, topic_displayInfo) == 0) { writeInfo(buffer); } - else if (!strcmp(topic, topic_stopOTA)) + else if (strcmp(topic, topic_stopOTA) == 0) { clearReaderInfo(); } -} \ No newline at end of file + delete[] buffer; +} diff --git a/Software/src/Display.h b/Software/src/Display.h index 17b318f..d0dcc96 100644 --- a/Software/src/Display.h +++ b/Software/src/Display.h @@ -1,20 +1,32 @@ #ifndef DISPLAY_H #define DISPLAY_H -#include + +#include +#include #define DISPLAY_BUFFER_SIZE 30 +#define SCREEN_WIDTH 128 +#define SCREEN_HEIGHT 64 +#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset) + class Display { private: - SSD1306Wire *display; + Adafruit_SSD1306 *display; int readerid; char ReaderInfo[DISPLAY_BUFFER_SIZE]; char Title[DISPLAY_BUFFER_SIZE]; char Info[DISPLAY_BUFFER_SIZE]; + // Helper function to center text horizontally at a given y coordinate. + void drawCenteredText(const char *text, int y); + public: + // The constructor takes the SDA and SCL pins (which are used to initialize Wire) + // and the reader ID. Display(int sda, int scl, int readerid); + void createReaderInfo(const char *state); void clearReaderInfo(); void writeReaderInfo(const char *text); @@ -23,4 +35,5 @@ public: void updateDisplay(); void updateByMQTT(const char *topic, byte *payload, unsigned int length); }; -#endif \ No newline at end of file + +#endif