From: Nils Date: Fri, 15 Dec 2023 01:45:03 +0000 (+0100) Subject: Added web-server, restructuring X-Git-Url: https://gitweb.forssennils.se/?a=commitdiff_plain;h=fa8b8d3992058457f3f011b853d8767fa4974a20;p=e-paper-project.git Added web-server, restructuring --- diff --git a/e-paper-project/bmp.cpp b/e-paper-project/bmp.cpp new file mode 100644 index 0000000..6e0798d --- /dev/null +++ b/e-paper-project/bmp.cpp @@ -0,0 +1,46 @@ +#include "include/bmp.h" +#include "include/sd_card.h" + +BMP::BMP(const char* filename) : + bmp_file{SD_card_fs::get_file(filename)}, + data_idx{0} +{ + + bmp_file->seek(10); // idx of 4 bytes representing start of image data + + data_idx = bmp_file->read(); + + for(uint8_t i{0}; i < 3; i++) + { + data_idx << 8; + data_idx |= bmp_file->read(); + } + + bmp_file->seek(data_idx); +} + +char BMP::read_pixel() +{ + return bmp_file->read(); +} + +void BMP::read_pixel(const char* buffer, const uint32_t len) +{ + bmp_file->read((uint8_t*)buffer, len); +} + +uint32_t BMP::position() const +{ + return bmp_file->position(); +} + +uint32_t BMP::available() const +{ + return bmp_file->available(); +} + +void BMP::seek(const uint32_t pos) +{ + if (pos < data_idx) bmp_file->seek(data_idx); + else bmp_file->seek(pos); +} diff --git a/e-paper-project/e-paper-project.ino b/e-paper-project/e-paper-project.ino new file mode 100644 index 0000000..7609ffe --- /dev/null +++ b/e-paper-project/e-paper-project.ino @@ -0,0 +1,42 @@ +#include "include/sd_card.h" +#include "include/bmp.h" +#include "include/web_server.h" + +/** + * @file e-paper-project.ino + * @author Nils Forssén (nilsforssen.se) + * @brief + * Project-sketch to fetch images from an web-server, process them (scaling and dithering) + * and then display them on an E-paper-display (SPI). Should switch image every 24 hours + * and go to sleep in between. Should support adding, removing and listing images on SD-card + * via a webserver as long as a physical switch is set high. When switched low, the + * device go back to the daily sleep->image->sleep cycle. + * + * @version 1.0 + * @date 2023-12-13 + * + * @copyright Copyright (c) 2023 + */ + + +/** + * Connect the SPI bus to SD-card and E-paper + * MOSI - GPIO 23 + * MISO - GPIO 19 + * SCLK - GPIO 18 + * CS - [SD to GPIO 5] or [E-paper to GPIO 17] +*/ + +void setup(){ + Serial.begin(115200); + + SD_card_fs::init_SD(5); + Web_server::init_wifi(); + Web_server::init_server(); + +} + +void loop() +{ + Web_server::handle_client(); +} \ No newline at end of file diff --git a/e-paper-project/epd_spi.cpp b/e-paper-project/epd_spi.cpp new file mode 100644 index 0000000..b2bab5d --- /dev/null +++ b/e-paper-project/epd_spi.cpp @@ -0,0 +1,155 @@ +#include "include/epd_spi.h" +#include "include/bmp.h" + +EPD_SPI_interface::EPD_SPI_interface(const epd_spi_pinout& p) : pinout{p} +{ + // init SPI pins + pinMode(pinout.pin_busy, INPUT); + pinMode(pinout.pin_rst, OUTPUT); + pinMode(pinout.pin_dc, OUTPUT); + pinMode(pinout.pin_clk, OUTPUT); + pinMode(pinout.pin_din, OUTPUT); + pinMode(pinout.pin_cs, OUTPUT); + + digitalWrite(pinout.pin_cs , HIGH); + digitalWrite(pinout.pin_clk, LOW); + + // init EPD + digitalWrite(pinout.pin_rst, HIGH); + delay(200); + digitalWrite(pinout.pin_rst, LOW); + delay(5); + digitalWrite(pinout.pin_rst, HIGH); + delay(200); + + // send init-data + waitfor_busyhigh(); + send_command(0x00); + send_byte(0xEF); + send_byte(0x08); + send_command(0x01); + send_byte(0x37); + send_byte(0x00); + send_byte(0x23); + send_byte(0x23); + send_command(0x03); + send_byte(0x00); + send_command(0x06); + send_byte(0xC7); + send_byte(0xC7); + send_byte(0x1D); + send_command(0x30); + send_byte(0x3C); + send_command(0x41); + send_byte(0x00); + send_command(0x50); + send_byte(0x37); + send_command(0x60); + send_byte(0x22); + send_command(0x61); + send_byte(0x02); + send_byte(0x58); + send_byte(0x01); + send_byte(0xC0); + send_command(0xE3); + send_byte(0xAA); + delay(100); + send_command(0x50); + send_byte(0x37); + send_command(0x61); + send_byte(0x02); + send_byte(0x58); + send_byte(0x01); + send_byte(0xC0); + send_command(0x10); +} + +void EPD_SPI_interface::send_byte(byte data) +{ + digitalWrite(pinout.pin_dc, HIGH); + send_spi_data(data); +} + +void EPD_SPI_interface::send_command(byte command) +{ + digitalWrite(pinout.pin_dc, LOW); + send_spi_data(command); +} + +void EPD_SPI_interface::show() +{ + send_command(0x04); + waitfor_busyhigh(); + send_command(0x12); + waitfor_busyhigh(); + send_command(0x02); + waitfor_busylow(); + delay(200); +} + +void EPD_SPI_interface::sleep() +{ + delay(100); + send_command(0x07); + send_byte(0xA5); + delay(100); + digitalWrite(pinout.pin_rst, LOW); +} + +void EPD_SPI_interface::send_spi_data(byte data) +{ + digitalWrite(pinout.pin_cs, LOW); + + for (int i = 0; i < 8; i++) + { + if ((data & 0x80)) + { + digitalWrite(pinout.pin_din, HIGH); + } + else + { + digitalWrite(pinout.pin_din, LOW); + } + + data <<= 1; + digitalWrite(pinout.pin_clk, HIGH); + digitalWrite(pinout.pin_clk, LOW); + } + + digitalWrite(pinout.pin_cs, HIGH); +} + +void EPD_SPI_interface::waitfor_busyhigh() const +{ + while(!(digitalRead(pinout.pin_busy))); +} + +void EPD_SPI_interface::waitfor_busylow() const +{ + while(digitalRead(pinout.pin_busy)); +} + +void EPD_SPI_interface::display(std::unique_ptr bmp) +{ + bmp->seek(0); + for (uint32_t i{0}; i < EPD_HEIGHT; i++) + { + for (uint32_t j{0}; j < EPD_WIDTH / 2; i++) // Every byte is 2 pixels + { + send_byte(bmp->read_pixel()); + } + } + show(); +} + +void EPD_SPI_interface::fill(color c) +{ + for (uint32_t i{0}; i < EPD_HEIGHT; i++) + { + for (uint32_t j{0}; j < EPD_WIDTH / 2; i++) // Every byte is 2 pixels + { + send_byte((c << 4)|c); + } + } + show(); +} \ No newline at end of file diff --git a/e-paper-project/include/bmp.h b/e-paper-project/include/bmp.h new file mode 100644 index 0000000..aeb3624 --- /dev/null +++ b/e-paper-project/include/bmp.h @@ -0,0 +1,38 @@ +#ifndef BMP_H_ +#define BMP_H_ + +/** + * @file sd_card.h + * @author Nils Forssén (nilsforssen.se) + * @brief + * Useful filesystem functions for interacting with an SD-card + * + * @version 0.1 + * @date 2023-12-13 + * + * @copyright Copyright (c) 2023 + */ + +#include +#include + +class BMP +{ +public: + BMP(const char* filename); + ~BMP() = default; // Smart pointer closes itself! + + char read_pixel(); + void read_pixel(const char* buffer, const uint32_t len); + uint32_t position() const; + uint32_t available() const; + void seek(const uint32_t pos); + +protected: +private: + std::unique_ptr bmp_file; + uint32_t data_idx; +}; + + +#endif \ No newline at end of file diff --git a/e-paper-project/include/epd_spi.h b/e-paper-project/include/epd_spi.h new file mode 100644 index 0000000..d19be33 --- /dev/null +++ b/e-paper-project/include/epd_spi.h @@ -0,0 +1,55 @@ +#ifndef SIMPLE_SPI_H_ +#define SIMPLE_SPI_H_ + +#include +#include + +#define EPD_WIDTH 600 +#define EPD_HEIGHT 448 + +enum color: byte +{ + EPD_5IN65F_BLACK, /// 000 + EPD_5IN65F_WHITE, /// 001 + EPD_5IN65F_GREEN, /// 010 + EPD_5IN65F_BLUE, /// 011 + EPD_5IN65F_RED, /// 100 + EPD_5IN65F_YELLOW, /// 101 + EPD_5IN65F_ORANGE /// 110 +}; + +struct epd_spi_pinout +{ + const uint8_t pin_busy; + const uint8_t pin_rst; + const uint8_t pin_dc; + const uint8_t pin_cs; + const uint8_t pin_clk; + const uint8_t pin_din; +}; + +class BMP; + +class EPD_SPI_interface +{ +public: + EPD_SPI_interface(const epd_spi_pinout& p); + ~EPD_SPI_interface() = default; + + void send_byte(byte data); + void send_command(byte command); + void display(std::unique_ptr bmp); + void fill(color c); + + void show(); + void sleep(); +protected: +private: + void send_spi_data(byte data); + void waitfor_busyhigh() const; + void waitfor_busylow() const; + + const epd_spi_pinout pinout; +}; + +#endif diff --git a/e-paper-project/include/sd_card.h b/e-paper-project/include/sd_card.h new file mode 100644 index 0000000..5544add --- /dev/null +++ b/e-paper-project/include/sd_card.h @@ -0,0 +1,38 @@ +#ifndef SD_CARD_H_ +#define SD_CARD_H_ + +/** + * @file sd_card.h + * @author Nils Forssén (nilsforssen.se) + * @brief + * Useful filesystem functions for interacting with an SD-card + * + * @date 2023-12-13 + * + * @copyright Copyright (c) 2023 + */ + +#include +#include + +typedef enum : uint8_t +{ + FS_OK = 0, + FS_FAIL = 1, + FS_WARNING = 2, +} fs_error_t; + +namespace SD_card_fs +{ + fs_error_t init_SD(const uint16_t cs); + fs_error_t create_dir(const char* path); + fs_error_t remove_dir(const char* path); + std::unique_ptr get_file(const char* path); + fs_error_t write_file(const char* path, const char* data); // Make sure data is null-terminated + fs_error_t append_file(const char* path, const char* data); // Make sure data is null-terminated + fs_error_t rename_file(const char* path1, const char* path2); + fs_error_t delete_file(const char* path); +}; + + +#endif \ No newline at end of file diff --git a/e-paper-project/include/web_HTML.h b/e-paper-project/include/web_HTML.h new file mode 100644 index 0000000..af901dd --- /dev/null +++ b/e-paper-project/include/web_HTML.h @@ -0,0 +1,29 @@ +#ifndef WEB_HTML_H_ +#define WEB_HTML_H_ + +/** + * @file web_HTML.h + * @author Nils Forssén (nilsforssen.se) + * @brief + * web-server functionality based on https://github.com/G6EJD/ESP32-ESP8266-File-Download-Upload-Delete-Stream-and-Directory/tree/master + * + * @date 2023-12-14 + * + * @copyright Copyright (c) 2023 + */ + +namespace HTML_data +{ + const char home_page_str[] PROGMEM = ""; + + const char file_upload_str[] PROGMEM = "

Select File to Upload




[Back]

"; + + const char upload_finished_str[] PROGMEM = "

File was successfully uploaded

"; + + const char append_page_header[] PROGMEM = "File Server

File Server

"; + + const char append_page_footer[] PROGMEM = ""; +}; + + +#endif \ No newline at end of file diff --git a/e-paper-project/include/web_server.h b/e-paper-project/include/web_server.h new file mode 100644 index 0000000..7e6d880 --- /dev/null +++ b/e-paper-project/include/web_server.h @@ -0,0 +1,35 @@ +#ifndef WEB_SERVER_H_ +#define WEB_SERVER_H_ + +/** + * @file web_server.h + * @author Nils Forssén (nilsforssen.se) + * @brief + * web-server functionality based on https://github.com/G6EJD/ESP32-ESP8266-File-Download-Upload-Delete-Stream-and-Directory/tree/master + * + * @date 2023-12-14 + * + * @copyright Copyright (c) 2023 + */ + +#ifdef ESP8266 + #include + #include + #include +#else + #include + #include +#endif + +#include "credentials.h" + +#define SERVER_PORT 80 + +namespace Web_server +{ + void init_wifi(); + void init_server(); + void handle_client(); +}; + +#endif \ No newline at end of file diff --git a/e-paper-project/sd_card.cpp b/e-paper-project/sd_card.cpp new file mode 100644 index 0000000..e6a940f --- /dev/null +++ b/e-paper-project/sd_card.cpp @@ -0,0 +1,110 @@ +#include "include/sd_card.h" + +namespace SD_card_fs +{ + fs_error_t init_SD(const uint16_t cs) + { + if(!SD.begin(cs)){ + Serial.println("Card Mount Failed"); + return FS_FAIL; + } + uint8_t cardType = SD.cardType(); + + if(cardType == CARD_NONE){ + Serial.println("No SD card attached"); + return FS_FAIL; + } + + Serial.printf("SD card initialized!\nSize: %lluMB\n", SD.cardSize() / (1024 * 1024)); + return FS_OK; + } + + fs_error_t create_dir(const char* path) + { + if(SD.mkdir(path)){ + Serial.printf("Created directory: %s\n", path); + return FS_OK; + } else { + Serial.printf("failed to create directory: %s\n", path); + return FS_FAIL; + } + } + + fs_error_t remove_dir(const char* path) + { + if(SD.rmdir(path)){ + Serial.printf("Removed directory: %s\n", path); + return FS_OK; + } else { + Serial.printf("failed to remove directory: %s\n", path); + return FS_FAIL; + } + } + + std::unique_ptr get_file(const char* path) + { + File* file = new File{SD.open(path)}; + if(!(*file)){ + Serial.printf("failed to open file: %s\n", path); + return nullptr; + } + return std::unique_ptr{file}; + } + + fs_error_t write_file(const char* path, const char* data) + { + File file = SD.open(path, FILE_WRITE); + if(!file){ + Serial.printf("failed to open file: %s\n", path); + return FS_FAIL; + } + + if(file.print(data)){ + Serial.printf("File written: %s\n", path); + file.close(); + return FS_OK; + } else { + Serial.printf("Write failed: %s\n", path); + file.close(); + return FS_FAIL; + } + } + + fs_error_t append_file(const char* path, const char* data){ + File file = SD.open(path, FILE_APPEND); + if(!file){ + Serial.printf("failed to open file for appending: %s\n", path); + return FS_FAIL; + } + + if(file.print(data)){ + Serial.printf("Message appended: %s\n", path); + file.close(); + return FS_OK; + } else { + Serial.printf("Append failed: %s\n", path); + file.close(); + return FS_FAIL; + } + } + + fs_error_t rename_file(const char* path1, const char* path2){ + if (SD.rename(path1, path2)) { + Serial.printf("File renamed: %s to %s\n", path1, path2); + return FS_OK; + } else { + Serial.printf("Rename failed: %s to %s\n", path1, path2); + return FS_FAIL; + } + } + + fs_error_t delete_file(const char* path){ + if(SD.remove(path)){ + Serial.printf("File deleted: %s\n", path); + return FS_OK; + } else { + Serial.printf("Delete failed: %s\n", path); + return FS_FAIL; + } + } +} \ No newline at end of file diff --git a/e-paper-project/web_server.cpp b/e-paper-project/web_server.cpp new file mode 100644 index 0000000..eeb8fb9 --- /dev/null +++ b/e-paper-project/web_server.cpp @@ -0,0 +1,295 @@ +#include "include/web_server.h" +#include "include/web_HTML.h" + +#ifdef ESP8266 + static ESP8266WebServer server{SERVER_PORT}; +#else + static ESP32WebServer server{SERVER_PORT}; +#endif + +static void send_HTML_page(const char* webpage) +{ + server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); + server.sendHeader("Pragma", "no-cache"); + server.sendHeader("Expires", "-1"); + server.setContentLength(CONTENT_LENGTH_UNKNOWN); + server.send(200, "text/html", ""); // Empty content inhibits Content-length header so we have to close the socket ourselves. + server.sendContent(HTML_data::append_page_header); + + server.sendContent(webpage); + server.sendContent(""); + server.client().stop(); +} + +static void home_page() +{ + send_HTML_page(HTML_data::home_page_str); +} + +static void file_upload() +{ + send_HTML_page(HTML_data::file_upload_str); +} + +static void handle_file_upload() +{ + HTTPUpload &uploadfile = server.upload(); + + if (uploadfile.status == UPLOAD_FILE_START) + { + String filename {uploadfile.filename}; + if (!filename.startsWith("/")) + filename = "/" + filename; + + Serial.print("Upload File Name: "); + Serial.println(filename); + // SD.remove(filename); // Remove a previous version, otherwise data is appended the file again + // UploadFile = SD.open(filename, FILE_WRITE); // Open the file for writing in SPIFFS (create it, if doesn't exist) + } + else if (uploadfile.status == UPLOAD_FILE_WRITE) + { + Serial.println("Writing file somewhere"); + } + else if (uploadfile.status == UPLOAD_FILE_END) + { + Serial.print("Upload Size: "); + Serial.println(uploadfile.totalSize); + } +} + +namespace Web_server +{ + void init_server() + { + server.on("/", home_page); + server.on("/upload", file_upload); + server.on("/fupload", HTTP_POST,[](){server.send(200);}, handle_file_upload); + //server.on("/delete", file_delete); + //server.on("/dir", SD_dir); + Serial.println("Web-server starting!"); + server.begin(); + } + + void init_wifi() + { + WiFi.mode(WIFI_STA); + WiFi.begin(ssid, passw); + Serial.println("Connecting"); + + while(WiFi.status() != WL_CONNECTED){ + Serial.print("."); + delay(500); + } + + Serial.println("\nConnected to the WiFi network"); + Serial.print("Local ESP32 IP: "); + Serial.println(WiFi.localIP()); + } + + void handle_client() + { + server.handleClient(); + } +}; + + + + + +/* +void Web_server::SD_dir() +{ + if (SD_present) + { + File root = SD.open("/"); + if (root) + { + root.rewindDirectory(); + SendHTML_Header(); + webpage += F("

SD Card Contents


"); + webpage += F(""); + webpage += F(""); + printDirectory("/", 0); + webpage += F("
Name/TypeType File/DirFile Size
"); + SendHTML_Content(); + root.close(); + } + else + { + SendHTML_Header(); + webpage += F("

No Files Found

"); + } + append_page_footer(); + SendHTML_Content(); + SendHTML_Stop(); // Stop is needed because no content length was sent + } + else + ReportSDNotPresent(); +} + + void printDirectory(const char *dirname, uint8_t levels) + { + File root = SD.open(dirname); + #ifdef ESP8266 + root.rewindDirectory(); // Only needed for ESP8266 + #endif + if (!root) + { + return; + } + if (!root.isDirectory()) + { + return; + } + File file = root.openNextFile(); + while (file) + { + if (webpage.length() > 1000) + { + SendHTML_Content(); + } + if (file.isDirectory()) + { + Serial.println(String(file.isDirectory() ? "Dir " : "File ") + String(file.name())); + webpage += "" + String(file.isDirectory() ? "Dir" : "File") + "" + String(file.name()) + ""; + printDirectory(file.name(), levels - 1); + } + else + { + // Serial.print(String(file.name())+"\t"); + webpage += "" + String(file.name()) + ""; + Serial.print(String(file.isDirectory() ? "Dir " : "File ") + String(file.name()) + "\t"); + webpage += "" + String(file.isDirectory() ? "Dir" : "File") + ""; + int bytes = file.size(); + String fsize = ""; + if (bytes < 1024) + fsize = String(bytes) + " B"; + else if (bytes < (1024 * 1024)) + fsize = String(bytes / 1024.0, 3) + " KB"; + else if (bytes < (1024 * 1024 * 1024)) + fsize = String(bytes / 1024.0 / 1024.0, 3) + " MB"; + else + fsize = String(bytes / 1024.0 / 1024.0 / 1024.0, 3) + " GB"; + webpage += "" + fsize + ""; + Serial.println(String(fsize)); + } + file = root.openNextFile(); + } + file.close(); + } + + void SD_file_stream(String filename) + { + if (SD_present) + { + File dataFile = SD.open("/" + filename, FILE_READ); // Now read data from SD Card + Serial.print("Streaming file: "); + Serial.println(filename); + if (dataFile) + { + if (dataFile.available()) + { // If data is available and present + String dataType = "application/octet-stream"; + if (server.streamFile(dataFile, dataType) != dataFile.size()) + { + Serial.print(F("Sent less data than expected!")); + } + } + dataFile.close(); // close the file: + } + else + ReportFileNotPresent("Cstream"); + } + else + ReportSDNotPresent(); + } + + void File_Delete() + { + if (server.args() > 0) + { // Arguments were received + if (server.hasArg("delete")) + SD_file_delete(server.arg(0)); + } + else + SelectInput("Select a File to Delete", "delete", "delete"); + } + + void SD_file_delete(String filename) + { // Delete the file + if (SD_present) + { + SendHTML_Header(); + File dataFile = SD.open("/" + filename, FILE_READ); // Now read data from SD Card + Serial.print("Deleting file: "); + Serial.println(filename); + if (dataFile) + { + if (SD.remove("/" + filename)) + { + Serial.println(F("File deleted successfully")); + webpage += "

File '" + filename + "' has been erased

"; + webpage += F("[Back]

"); + } + else + { + webpage += F("

File was not deleted - error

"); + webpage += F("[Back]

"); + } + } + else + ReportFileNotPresent("delete"); + append_page_footer(); + SendHTML_Content(); + SendHTML_Stop(); + } + else + ReportSDNotPresent(); + } + + void SendHTML_Header() + { + server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); + server.sendHeader("Pragma", "no-cache"); + server.sendHeader("Expires", "-1"); + server.setContentLength(CONTENT_LENGTH_UNKNOWN); + server.send(200, "text/html", ""); // Empty content inhibits Content-length header so we have to close the socket ourselves. + append_page_header(); + server.sendContent(webpage); + webpage = ""; + } + + + void ReportSDNotPresent() + { + SendHTML_Header(); + webpage += F("

No SD Card present

"); + webpage += F("[Back]

"); + append_page_footer(); + SendHTML_Content(); + SendHTML_Stop(); + } + + void ReportFileNotPresent(String target) + { + SendHTML_Header(); + webpage += F("

File does not exist

"); + webpage += F("[Back]

"; + append_page_footer(); + SendHTML_Content(); + SendHTML_Stop(); + } + + void ReportCouldNotCreateFile(String target) + { + SendHTML_Header(); + webpage += F("

Could Not Create Uploaded File (write-protected?)

"); + webpage += F("[Back]

"; + append_page_footer(); + SendHTML_Content(); + SendHTML_Stop(); + } +} +*/ \ No newline at end of file diff --git a/src/bmp.cpp b/src/bmp.cpp deleted file mode 100644 index e32dfca..0000000 --- a/src/bmp.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include "include/bmp.h" -#include "include/sd_card.h" - -BMP::BMP(const char* filename) : - bmp_file{SD_card_fs::get_file(filename)}, - data_idx{0} -{ - - bmp_file->seek(10); // idx of 4 bytes representing start of image data - - data_idx = bmp_file->read(); - - for(uint8_t i{0}; i < 3; i++) - { - data_idx << 8; - data_idx |= bmp_file->read(); - } - - bmp_file->seek(data_idx); -} - -byte BMP::read_pixel() -{ - return bmp_file->read(); -} - -void BMP::read_pixel(const char* buffer, const uint32_t len) -{ - bmp_file->read(buffer, len); -} - -uint32_t BMP::position() const -{ - return bmp_file->position(); -} - -uint32_t BMP::available() const -{ - return bmp_file->available(); -} - -void BMP::seek(const uint32_t pos) -{ - if (pos < data_idx) bmp_file->seek(data_idx); - else bmp_file->seek(pos); -} diff --git a/src/e-paper-project.ino b/src/e-paper-project.ino deleted file mode 100644 index 66d5cd3..0000000 --- a/src/e-paper-project.ino +++ /dev/null @@ -1,57 +0,0 @@ -#include "include/sd_card.h" -#include "include/bmp.h" -#include "Arduino.h" - -/** - * @file e-paper-project.ino - * @author Nils Forssén (nilsforssen.se) - * @brief - * Project-sketch to fetch images from an web-server, process them (scaling and dithering) - * and then display them on an E-paper-display (SPI). Should switch image every 24 hours - * and go to sleep in between. Should support adding, removing and listing images on SD-card - * via a webserver as long as a physical switch is set high. When switched low, the - * device go back to the daily sleep->image->sleep cycle. - * - * @version 0.1 - * @date 2023-12-13 - * - * @copyright Copyright (c) 2023 - */ - - -/** - * Connect the SPI bus to SD-card and E-paper - * MOSI - GPIO 23 - * MISO - GPIO 19 - * SCLK - GPIO 18 - * CS - [SD to GPIO 5] or [E-paper to GPIO 17] -*/ - - -void setup(){ - Serial.begin(115200); - - if(!SD.begin(5)){ - Serial.println("Card Mount Failed"); - return; - } - uint8_t cardType = SD.cardType(); - - if(cardType == CARD_NONE){ - Serial.println("No SD card attached"); - return; - } - - Serial.printf("SD card initialized!\nSize: %lluMB\n", SD.cardSize() / (1024 * 1024)); -} - -void loop() -{ - BMP bmp_file{"/download.bmp"}; - while (true) - { - Serial.printf("Read pixel of txt file: %x\n", bmp_file.read_pixel() & 0xff); - delay(1000); - } - -} \ No newline at end of file diff --git a/src/epd_spi.cpp b/src/epd_spi.cpp deleted file mode 100644 index b2bab5d..0000000 --- a/src/epd_spi.cpp +++ /dev/null @@ -1,155 +0,0 @@ -#include "include/epd_spi.h" -#include "include/bmp.h" - -EPD_SPI_interface::EPD_SPI_interface(const epd_spi_pinout& p) : pinout{p} -{ - // init SPI pins - pinMode(pinout.pin_busy, INPUT); - pinMode(pinout.pin_rst, OUTPUT); - pinMode(pinout.pin_dc, OUTPUT); - pinMode(pinout.pin_clk, OUTPUT); - pinMode(pinout.pin_din, OUTPUT); - pinMode(pinout.pin_cs, OUTPUT); - - digitalWrite(pinout.pin_cs , HIGH); - digitalWrite(pinout.pin_clk, LOW); - - // init EPD - digitalWrite(pinout.pin_rst, HIGH); - delay(200); - digitalWrite(pinout.pin_rst, LOW); - delay(5); - digitalWrite(pinout.pin_rst, HIGH); - delay(200); - - // send init-data - waitfor_busyhigh(); - send_command(0x00); - send_byte(0xEF); - send_byte(0x08); - send_command(0x01); - send_byte(0x37); - send_byte(0x00); - send_byte(0x23); - send_byte(0x23); - send_command(0x03); - send_byte(0x00); - send_command(0x06); - send_byte(0xC7); - send_byte(0xC7); - send_byte(0x1D); - send_command(0x30); - send_byte(0x3C); - send_command(0x41); - send_byte(0x00); - send_command(0x50); - send_byte(0x37); - send_command(0x60); - send_byte(0x22); - send_command(0x61); - send_byte(0x02); - send_byte(0x58); - send_byte(0x01); - send_byte(0xC0); - send_command(0xE3); - send_byte(0xAA); - delay(100); - send_command(0x50); - send_byte(0x37); - send_command(0x61); - send_byte(0x02); - send_byte(0x58); - send_byte(0x01); - send_byte(0xC0); - send_command(0x10); -} - -void EPD_SPI_interface::send_byte(byte data) -{ - digitalWrite(pinout.pin_dc, HIGH); - send_spi_data(data); -} - -void EPD_SPI_interface::send_command(byte command) -{ - digitalWrite(pinout.pin_dc, LOW); - send_spi_data(command); -} - -void EPD_SPI_interface::show() -{ - send_command(0x04); - waitfor_busyhigh(); - send_command(0x12); - waitfor_busyhigh(); - send_command(0x02); - waitfor_busylow(); - delay(200); -} - -void EPD_SPI_interface::sleep() -{ - delay(100); - send_command(0x07); - send_byte(0xA5); - delay(100); - digitalWrite(pinout.pin_rst, LOW); -} - -void EPD_SPI_interface::send_spi_data(byte data) -{ - digitalWrite(pinout.pin_cs, LOW); - - for (int i = 0; i < 8; i++) - { - if ((data & 0x80)) - { - digitalWrite(pinout.pin_din, HIGH); - } - else - { - digitalWrite(pinout.pin_din, LOW); - } - - data <<= 1; - digitalWrite(pinout.pin_clk, HIGH); - digitalWrite(pinout.pin_clk, LOW); - } - - digitalWrite(pinout.pin_cs, HIGH); -} - -void EPD_SPI_interface::waitfor_busyhigh() const -{ - while(!(digitalRead(pinout.pin_busy))); -} - -void EPD_SPI_interface::waitfor_busylow() const -{ - while(digitalRead(pinout.pin_busy)); -} - -void EPD_SPI_interface::display(std::unique_ptr bmp) -{ - bmp->seek(0); - for (uint32_t i{0}; i < EPD_HEIGHT; i++) - { - for (uint32_t j{0}; j < EPD_WIDTH / 2; i++) // Every byte is 2 pixels - { - send_byte(bmp->read_pixel()); - } - } - show(); -} - -void EPD_SPI_interface::fill(color c) -{ - for (uint32_t i{0}; i < EPD_HEIGHT; i++) - { - for (uint32_t j{0}; j < EPD_WIDTH / 2; i++) // Every byte is 2 pixels - { - send_byte((c << 4)|c); - } - } - show(); -} \ No newline at end of file diff --git a/src/include/bmp.h b/src/include/bmp.h deleted file mode 100644 index bcb048c..0000000 --- a/src/include/bmp.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef BMP_H_ -#define BMP_H_ - -/** - * @file sd_card.h - * @author Nils Forssén (nilsforssen.se) - * @brief - * Useful filesystem functions for interacting with an SD-card - * - * @version 0.1 - * @date 2023-12-13 - * - * @copyright Copyright (c) 2023 - */ - -#include -#include - -class BMP -{ -public: - BMP(const char* filename); - ~BMP() = default; // Smart pointer closes itself! - - byte read_pixel(); - void read_pixel(const char* buffer, const uint32_t len); - uint32_t position() const; - uint32_t available() const; - void seek(const uint32_t pos); - -protected: -private: - std::unique_ptr bmp_file; - uint32_t data_idx; -}; - - -#endif \ No newline at end of file diff --git a/src/include/epd_spi.h b/src/include/epd_spi.h deleted file mode 100644 index d19be33..0000000 --- a/src/include/epd_spi.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef SIMPLE_SPI_H_ -#define SIMPLE_SPI_H_ - -#include -#include - -#define EPD_WIDTH 600 -#define EPD_HEIGHT 448 - -enum color: byte -{ - EPD_5IN65F_BLACK, /// 000 - EPD_5IN65F_WHITE, /// 001 - EPD_5IN65F_GREEN, /// 010 - EPD_5IN65F_BLUE, /// 011 - EPD_5IN65F_RED, /// 100 - EPD_5IN65F_YELLOW, /// 101 - EPD_5IN65F_ORANGE /// 110 -}; - -struct epd_spi_pinout -{ - const uint8_t pin_busy; - const uint8_t pin_rst; - const uint8_t pin_dc; - const uint8_t pin_cs; - const uint8_t pin_clk; - const uint8_t pin_din; -}; - -class BMP; - -class EPD_SPI_interface -{ -public: - EPD_SPI_interface(const epd_spi_pinout& p); - ~EPD_SPI_interface() = default; - - void send_byte(byte data); - void send_command(byte command); - void display(std::unique_ptr bmp); - void fill(color c); - - void show(); - void sleep(); -protected: -private: - void send_spi_data(byte data); - void waitfor_busyhigh() const; - void waitfor_busylow() const; - - const epd_spi_pinout pinout; -}; - -#endif diff --git a/src/include/sd_card.h b/src/include/sd_card.h deleted file mode 100644 index 5677c3c..0000000 --- a/src/include/sd_card.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef SD_CARD_H_ -#define SD_CARD_H_ - -/** - * @file sd_card.h - * @author Nils Forssén (nilsforssen.se) - * @brief - * Useful filesystem functions for interacting with an SD-card - * - * @version 0.1 - * @date 2023-12-13 - * - * @copyright Copyright (c) 2023 - */ - -#include -#include - -// #include "SPI.h" - -typedef enum -{ - FS_OK = 0, - FS_FAIL = 1, - FS_WARNING = 2, -} fs_error_t; - -namespace SD_card_fs { - - fs_error_t create_dir(const char* path); - fs_error_t remove_dir(const char* path); - std::unique_ptr get_file(const char* path); - fs_error_t write_file(const char* path, const char* data); // Make sure data is null-terminated - fs_error_t append_file(const char* path, const char* data); // Make sure data is null-terminated - fs_error_t rename_file(const char* path1, const char* path2); - fs_error_t delete_file(const char* path); -}; - - -#endif \ No newline at end of file diff --git a/src/sd_card.cpp b/src/sd_card.cpp deleted file mode 100644 index e1b292d..0000000 --- a/src/sd_card.cpp +++ /dev/null @@ -1,93 +0,0 @@ -#include "include/sd_card.h" - -namespace SD_card_fs -{ - fs_error_t create_dir(const char* path) - { - if(SD.mkdir(path)){ - Serial.printf("Created directory: %s\n", path); - return FS_OK; - } else { - Serial.printf("failed to create directory: %s\n", path); - return FS_FAIL; - } - } - - fs_error_t remove_dir(const char* path) - { - if(SD.rmdir(path)){ - Serial.printf("Removed directory: %s\n", path); - return FS_OK; - } else { - Serial.printf("failed to remove directory: %s\n", path); - return FS_FAIL; - } - } - - std::unique_ptr get_file(const char* path) - { - File* file = new File{SD.open(path)}; - if(!(*file)){ - Serial.printf("failed to open file: %s\n", path); - return nullptr; - } - return std::unique_ptr{file}; - } - - fs_error_t write_file(const char* path, const char* data) - { - File file = SD.open(path, FILE_WRITE); - if(!file){ - Serial.printf("failed to open file: %s\n", path); - return FS_FAIL; - } - - if(file.print(data)){ - Serial.printf("File written: %s\n", path); - file.close(); - return FS_OK; - } else { - Serial.printf("Write failed: %s\n", path); - file.close(); - return FS_FAIL; - } - } - - fs_error_t append_file(const char* path, const char* data){ - File file = SD.open(path, FILE_APPEND); - if(!file){ - Serial.printf("failed to open file for appending: %s\n", path); - return FS_FAIL; - } - - if(file.print(data)){ - Serial.printf("Message appended: %s\n", path); - file.close(); - return FS_OK; - } else { - Serial.printf("Append failed: %s\n", path); - file.close(); - return FS_FAIL; - } - } - - fs_error_t rename_file(const char* path1, const char* path2){ - if (SD.rename(path1, path2)) { - Serial.printf("File renamed: %s to %s\n", path1, path2); - return FS_OK; - } else { - Serial.printf("Rename failed: %s to %s\n", path1, path2); - return FS_FAIL; - } - } - - fs_error_t delete_file(const char* path){ - if(SD.remove(path)){ - Serial.printf("File deleted: %s\n", path); - return FS_OK; - } else { - Serial.printf("Delete failed: %s\n", path); - return FS_FAIL; - } - } -} \ No newline at end of file