diff --git a/README.md b/README.md index 2df5da7..2362bbd 100644 --- a/README.md +++ b/README.md @@ -42,8 +42,8 @@ se synchroniser avec le firmware et potentiellement le mettre à jour. - [ ] Contrôle des modules - [x] RFID (base) - [ ] RFID (avancé, écriture des tags) - - [ ] LCD (base) - - [ ] LCD (animations) + - [x] LCD (base) + - [x] LCD (animations) - [ ] LCD (UI) - [ ] Audio (sons de figurines) - [ ] Audio (sons d'UI) diff --git a/include/LCD.h b/include/LCD.h new file mode 100644 index 0000000..b3111a1 --- /dev/null +++ b/include/LCD.h @@ -0,0 +1,46 @@ +// +// Created by Teo-CD on 17/10/23. +// + +#ifndef JIN_BARBAPAPA_LCD_H +#define JIN_BARBAPAPA_LCD_H + +#include +#include +#include + +#include + +#include "Com.h" +#include "IDs.h" +#include "Pinout.h" + +class LCD { +public: + LCD() : sd(SD) {}; + void init(); + /*** + * Check if time has passed and we should display a new frame. + * @return True if a new frame was displayed. + */ + bool checkAndDisplay(); + void startNewAnim(int8_t ID); +private: + Adafruit_PCD8544 lcd{pin_LCD_DC, pin_LCD_CS, pin_LCD_RST}; + + SDClass &sd; + /* Directory where the current animation frames are stored. */ + File animDir; + + /*** + * Array storing the bitmap that will be passed to the LCD. + * The LCD is 84x48 so that should be 504 bytes, but the row length (84) + * is not byte aligned. Thus, the last byte is padded, giving 88x48 = 528. + */ + static uint8_t bitmap[528]; + uint32_t lastFrameTime = 0; + /* Delay between two frames, in milliseconds. Above 10 FPS is mushy, avoid. */ + static constexpr uint32_t frameTarget = 1000 / 7; +}; + +#endif //JIN_BARBAPAPA_LCD_H diff --git a/src/LCD.cpp b/src/LCD.cpp new file mode 100644 index 0000000..0b9e478 --- /dev/null +++ b/src/LCD.cpp @@ -0,0 +1,65 @@ +// +// Created by Teo-CD on 17/10/23. +// + +#include "LCD.h" + +uint8_t LCD::bitmap[528] = {}; + +void LCD::init() { + lcd.begin(60, 4); + lcd.clearDisplay(); + lastFrameTime = millis(); + /* Needed to keep the display clean at boot. */ + lcd.display(); + /* TODO: JIN splash welcome ? */ +} + +void LCD::startNewAnim(int8_t ID) { + char directoryPath[15]; + uint8_t rawID = getRawId(ID); + + if (!SD.mediaPresent()) { + Com::sendComment("SD Card not present, cannot play animation"); + return; + } + if (!isValidId(ID)) { + Com::sendComment("Unknown ID for animation : %d", rawID); + return; + } + + /* Interrupt previous running animation if there's one. */ + if (animDir) + animDir.close(); + + /* TODO: If adding remove animation, change path + check isIdGone */ + snprintf(directoryPath, 15, "%s/ANIM", + (isIdCharacter(ID) ? charDirs : promoDirs)[rawID]); + animDir = SD.open(directoryPath); + if (!animDir) { + Com::sendComment("Could not open directory %s for ID %d", directoryPath, rawID); + return; + } + checkAndDisplay(); +} + +bool LCD::checkAndDisplay() { + if (!animDir || millis() - lastFrameTime < frameTarget) + return false; + + File frame = animDir.openNextFile(); + if (!frame) { + /* There are no frames anymore, the animation is complete. */ + animDir.close(); + return false; + } + frame.read(bitmap, 528); + frame.close(); + + lcd.clearDisplay(); + lcd.drawBitmap(0, 0, bitmap, 84, 48, 1); + lcd.display(); + + lastFrameTime = millis(); + return true; +} diff --git a/src/main.cpp b/src/main.cpp index 14c990f..6615fef 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,6 +3,7 @@ #include "Pinout.h" #include "Com.h" +#include "LCD.h" #include "RFID.h" __attribute__((noreturn)) int main() { @@ -44,15 +45,27 @@ __attribute__((noreturn)) int main() { digitalWrite(pin_NFC1_RST, HIGH); rfid.init(); + if (!SD.begin(BUILTIN_SDCARD)) + Com::sendComment("Could not use the SD Card."); + + LCD lcd; + digitalWrite(pin_LCD_RST, HIGH); + lcd.init(); + /* Main loop */ while (true) { int8_t tagEvent; + /* Display first, in case the RFID communication delays it too much. */ + lcd.checkAndDisplay(); + tagEvent = rfid.checkTags(); if (tagEvent) { Com::sendFigUpdate(tagEvent); + lcd.startNewAnim(tagEvent); } - delay(100); + /* TODO: Drop delay, WFE+timer interrupt(s) ? */ + delay(25); } }