From df4e78d57c7c85f540c82727072e64ba335f2f95 Mon Sep 17 00:00:00 2001 From: f321x Date: Sun, 26 Nov 2023 21:34:06 +0100 Subject: [PATCH] first upload --- include/GxEPD2_display_selection_new_style.h | 267 ++++++++++++++ include/GxEPD2_selection_check.h | 106 ++++++ include/GxEPD2_wiring_examples.h | 83 +++++ include/README | 39 ++ include/lightning_atm.h | 50 +++ lib/README | 46 +++ platformio.ini | 19 + src/main.cpp | 357 +++++++++++++++++++ test/README | 11 + 9 files changed, 978 insertions(+) create mode 100644 include/GxEPD2_display_selection_new_style.h create mode 100644 include/GxEPD2_selection_check.h create mode 100644 include/GxEPD2_wiring_examples.h create mode 100644 include/README create mode 100644 include/lightning_atm.h create mode 100644 lib/README create mode 100644 platformio.ini create mode 100644 src/main.cpp create mode 100644 test/README diff --git a/include/GxEPD2_display_selection_new_style.h b/include/GxEPD2_display_selection_new_style.h new file mode 100644 index 0000000..bb555f1 --- /dev/null +++ b/include/GxEPD2_display_selection_new_style.h @@ -0,0 +1,267 @@ +// Display Library example for SPI e-paper panels from Dalian Good Display and boards from Waveshare. +// Requires HW SPI and Adafruit_GFX. Caution: the e-paper panels require 3.3V supply AND data lines! +// +// Display Library based on Demo Example from Good Display: http://www.e-paper-display.com/download_list/downloadcategoryid=34&isMode=false.html +// +// Author: Jean-Marc Zingg +// +// Version: see library.properties +// +// Library: https://github.com/ZinggJM/GxEPD2 + +// Supporting Arduino Forum Topics: +// Waveshare e-paper displays with SPI: http://forum.arduino.cc/index.php?topic=487007.0 +// Good Display ePaper for Arduino: https://forum.arduino.cc/index.php?topic=436411.0 + +// NOTE: you may need to adapt or select for your wiring in the processor specific conditional compile sections below + +// select the display class (only one), matching the kind of display panel +#define GxEPD2_DISPLAY_CLASS GxEPD2_BW +//#define GxEPD2_DISPLAY_CLASS GxEPD2_3C +//#define GxEPD2_DISPLAY_CLASS GxEPD2_4C +//#define GxEPD2_DISPLAY_CLASS GxEPD2_7C + +// select the display driver class (only one) for your panel +//#define GxEPD2_DRIVER_CLASS GxEPD2_102 // GDEW0102T4 80x128, UC8175, (WFT0102CZA2) +#define GxEPD2_DRIVER_CLASS GxEPD2_150_BN // DEPG0150BN 200x200, SSD1681, (FPC8101), TTGO T5 V2.4.1 +///#define GxEPD2_DRIVER_CLASS GxEPD2_154 // GDEP015OC1 200x200, IL3829, (WFC0000CZ07), no longer available +///#define GxEPD2_DRIVER_CLASS GxEPD2_154_D67 // GDEH0154D67 200x200, SSD1681, (HINK-E154A07-A1) +//#define GxEPD2_DRIVER_CLASS GxEPD2_154_T8 // GDEW0154T8 152x152, UC8151 (IL0373), (WFT0154CZ17) +//#define GxEPD2_DRIVER_CLASS GxEPD2_154_M09 // GDEW0154M09 200x200, JD79653A, (WFT0154CZB3) +//#define GxEPD2_DRIVER_CLASS GxEPD2_154_M10 // GDEW0154M10 152x152, UC8151D, (WFT0154CZ17) +///#define GxEPD2_DRIVER_CLASS GxEPD2_154_GDEY0154D67 // GDEY0154D67 200x200, SSD1681, (FPC-B001 20.05.21) +//#define GxEPD2_DRIVER_CLASS GxEPD2_213 // GDE0213B1 122x250, IL3895, (HINK-E0213-G01), phased out +//#define GxEPD2_DRIVER_CLASS GxEPD2_213_B72 // GDEH0213B72 122x250, SSD1675A (IL3897), (HINK-E0213A22-A0 SLH1852) +//#define GxEPD2_DRIVER_CLASS GxEPD2_213_B73 // GDEH0213B73 122x250, SSD1675B, (HINK-E0213A22-A0 SLH1914) +//#define GxEPD2_DRIVER_CLASS GxEPD2_213_B74 // GDEM0213B74 122x250, SSD1680, FPC-7528B) +//#define GxEPD2_DRIVER_CLASS GxEPD2_213_flex // GDEW0213I5F 104x212, UC8151 (IL0373), (WFT0213CZ16) +//#define GxEPD2_DRIVER_CLASS GxEPD2_213_M21 // GDEW0213M21 104x212, UC8151 (IL0373), (WFT0213CZ16) +//#define GxEPD2_DRIVER_CLASS GxEPD2_213_T5D // GDEW0213T5D 104x212, UC8151D, (WFT0213CZ16) +//#define GxEPD2_DRIVER_CLASS GxEPD2_213_BN // DEPG0213BN 122x250, SSD1680, (FPC-7528B), TTGO T5 V2.4.1, V2.3.1 +//#define GxEPD2_DRIVER_CLASS GxEPD2_213_GDEY0213B74 // GDEY0213B74 122x250, SSD1680, (FPC-A002 20.04.08) +//#define GxEPD2_DRIVER_CLASS GxEPD2_260 // GDEW026T0 152x296, UC8151 (IL0373), (WFT0154CZ17) +//#define GxEPD2_DRIVER_CLASS GxEPD2_260_M01 // GDEW026M01 152x296, UC8151 (IL0373), (WFT0260CZB2) +//#define GxEPD2_DRIVER_CLASS GxEPD2_266_BN // DEPG0266BN 152x296, SSD1680, (FPC7510), TTGO T5 V2.66, TTGO T5 V2.4.1 +//#define GxEPD2_DRIVER_CLASS GxEPD2_266_GDEY0266T90 // GDEY0266T90 152x296, SSD1680, (FPC-A003 HB) +//#define GxEPD2_DRIVER_CLASS GxEPD2_270 // GDEW027W3 176x264, EK79652 (IL91874), (WFI0190CZ22) +//#define GxEPD2_DRIVER_CLASS GxEPD2_270_GDEY027T91 // GDEY027T91 176x264, SSD1680, (FB) +//#define GxEPD2_DRIVER_CLASS GxEPD2_290 // GDEH029A1 128x296, SSD1608 (IL3820), (E029A01-FPC-A1 SYX1553) +//#define GxEPD2_DRIVER_CLASS GxEPD2_290_T5 // GDEW029T5 128x296, UC8151 (IL0373), (WFT0290CZ10) +//#define GxEPD2_DRIVER_CLASS GxEPD2_290_T5D // GDEW029T5D 128x296, UC8151D, (WFT0290CZ10) +//#define GxEPD2_DRIVER_CLASS GxEPD2_290_I6FD // GDEW029I6FD 128x296, UC8151D, (WFT0290CZ10) +//#define GxEPD2_DRIVER_CLASS GxEPD2_290_T94 // GDEM029T94 128x296, SSD1680, (FPC-7519 rev.b) +//#define GxEPD2_DRIVER_CLASS GxEPD2_290_T94_V2 // GDEM029T94 128x296, SSD1680, (FPC-7519 rev.b), Waveshare 2.9" V2 variant +//#define GxEPD2_DRIVER_CLASS GxEPD2_290_BS // DEPG0290BS 128x296, SSD1680, (FPC-7519 rev.b) +//#define GxEPD2_DRIVER_CLASS GxEPD2_290_M06 // GDEW029M06 128x296, UC8151D, (WFT0290CZ10) +//#define GxEPD2_DRIVER_CLASS GxEPD2_290_GDEY029T94 // GDEY029T94 128x296, SSD1680, (FPC-A005 20.06.15) +//#define GxEPD2_DRIVER_CLASS GxEPD2_371 // GDEW0371W7 240x416, UC8171 (IL0324), (missing) +//#define GxEPD2_DRIVER_CLASS GxEPD2_370_TC1 // ED037TC1 280x480, SSD1677, (ICA-FU-20 ichia 2029), Waveshare 3.7" +//#define GxEPD2_DRIVER_CLASS GxEPD2_420 // GDEW042T2 400x300, UC8176 (IL0398), (WFT042CZ15) +//#define GxEPD2_DRIVER_CLASS GxEPD2_420_M01 // GDEW042M01 400x300, UC8176 (IL0398), (WFT042CZ15) +//#define GxEPD2_DRIVER_CLASS GxEPD2_420_GDEY042T91 // GDEY042T91 400x300, SSD1683 (no inking) +//#define GxEPD2_DRIVER_CLASS GxEPD2_583 // GDEW0583T7 600x448, UC8159c (IL0371), (missing) +//#define GxEPD2_DRIVER_CLASS GxEPD2_583_T8 // GDEW0583T8 648x480, EK79655 (GD7965), (WFT0583CZ61) +//#define GxEPD2_DRIVER_CLASS GxEPD2_583_GDEQ0583T31 // GDEQ0583T31 648x480, UC8179, (P583010-MF1-B) +//#define GxEPD2_DRIVER_CLASS GxEPD2_750 // GDEW075T8 640x384, UC8159c (IL0371), (WF0583CZ09) +//#define GxEPD2_DRIVER_CLASS GxEPD2_750_T7 // GDEW075T7 800x480, EK79655 (GD7965), (WFT0583CZ61) +//#define GxEPD2_DRIVER_CLASS GxEPD2_750_YT7 // GDEY075T7 800x480, UC8179 (GD7965), (FPC-C001 20.8.20) +//#define GxEPD2_DRIVER_CLASS GxEPD2_1160_T91 // GDEH116T91 960x640, SSD1677, (none or hidden) +//#define GxEPD2_DRIVER_CLASS GxEPD2_1248 // GDEW1248T3 1304x984, UC8179, (WFT1248BZ23,WFT1248BZ24) +// 3-color e-papers +//#define GxEPD2_DRIVER_CLASS GxEPD2_154c // GDEW0154Z04 200x200, IL0376F, (WFT0000CZ04), no longer available +//#define GxEPD2_DRIVER_CLASS GxEPD2_154_Z90c // GDEH0154Z90 200x200, SSD1681, (HINK-E154A07-A1) +//#define GxEPD2_DRIVER_CLASS GxEPD2_213c // GDEW0213Z16 104x212, UC8151 (IL0373), (WFT0213CZ16) +//#define GxEPD2_DRIVER_CLASS GxEPD2_213_Z19c // GDEH0213Z19 104x212, UC8151D, (HINK-E0213A20-A2 2020-11-19) +//#define GxEPD2_DRIVER_CLASS GxEPD2_213_Z98c // GDEY0213Z98 122x250, SSD1680, (FPC-A002 20.04.08) +//#define GxEPD2_DRIVER_CLASS GxEPD2_266c // GDEY0266Z90 152x296, SSD1680, (FPC-7510) +//#define GxEPD2_DRIVER_CLASS GxEPD2_270c // GDEW027C44 176x264, IL91874, (WFI0190CZ22) +//#define GxEPD2_DRIVER_CLASS GxEPD2_290c // GDEW029Z10 128x296, UC8151 (IL0373), (WFT0290CZ10) +//#define GxEPD2_DRIVER_CLASS GxEPD2_290_Z13c // GDEH029Z13 128x296, UC8151D, (HINK-E029A10-A3 20160809) +//#define GxEPD2_DRIVER_CLASS GxEPD2_290_C90c // GDEM029C90 128x296, SSD1680, (FPC-7519 rev.b) +//#define GxEPD2_DRIVER_CLASS GxEPD2_420c // GDEW042Z15 400x300, UC8176 (IL0398), (WFT0420CZ15) +//#define GxEPD2_DRIVER_CLASS GxEPD2_420c_Z21 // GDEQ042Z21 400x300, UC8276, (hidden) +//#define GxEPD2_DRIVER_CLASS GxEPD2_583c // GDEW0583Z21 600x448, UC8159c (IL0371), (missing) +//#define GxEPD2_DRIVER_CLASS GxEPD2_583c_Z83 // GDEW0583Z83 648x480, EK79655 (GD7965), (WFT0583CZ61) +//#define GxEPD2_DRIVER_CLASS GxEPD2_750c // GDEW075Z09 640x384, UC8159c (IL0371), (WF0583CZ09) +//#define GxEPD2_DRIVER_CLASS GxEPD2_750c_Z08 // GDEW075Z08 800x480, EK79655 (GD7965), (WFT0583CZ61) +//#define GxEPD2_DRIVER_CLASS GxEPD2_750c_Z90 // GDEH075Z90 880x528, SSD1677, (HINK-E075A07-A0) +//#define GxEPD2_DRIVER_CLASS GxEPD2_1248c // GDEY1248Z51 1304x984, UC8179, (WFT1248BZ23,WFT1248BZ24) +// 4-color e-paper +//#define GxEPD2_DRIVER_CLASS GxEPD2_437c // Waveshare 4.37" 4-color +// 7-color e-paper +//#define GxEPD2_DRIVER_CLASS GxEPD2_565c // Waveshare 5.65" 7-color +//#define GxEPD2_DRIVER_CLASS GxEPD2_730c_GDEY073D46 // GDEY073D46 800x480 7-color, (N-FPC-001 2021.11.26) +// grey levels parallel IF e-papers on Waveshare e-Paper IT8951 Driver HAT +//#define GxEPD2_DRIVER_CLASS GxEPD2_it60 // ED060SCT 800x600 +//#define GxEPD2_DRIVER_CLASS GxEPD2_it60_1448x1072 // ED060KC1 1448x1072 +//#define GxEPD2_DRIVER_CLASS GxEPD2_it78_1872x1404 // ED078KC2 1872x1404 +//#define GxEPD2_DRIVER_CLASS GxEPD2_it103_1872x1404 // ES103TC1 1872x1404 + +// SS is usually used for CS. define here for easy change +#ifndef EPD_CS +#define EPD_CS SS +#endif + +#if defined(GxEPD2_DISPLAY_CLASS) && defined(GxEPD2_DRIVER_CLASS) + +// somehow there should be an easier way to do this +#define GxEPD2_BW_IS_GxEPD2_BW true +#define GxEPD2_3C_IS_GxEPD2_3C true +#define GxEPD2_4C_IS_GxEPD2_4C true +#define GxEPD2_7C_IS_GxEPD2_7C true +#define GxEPD2_1248_IS_GxEPD2_1248 true +#define GxEPD2_1248c_IS_GxEPD2_1248c true +#define IS_GxEPD(c, x) (c##x) +#define IS_GxEPD2_BW(x) IS_GxEPD(GxEPD2_BW_IS_, x) +#define IS_GxEPD2_3C(x) IS_GxEPD(GxEPD2_3C_IS_, x) +#define IS_GxEPD2_4C(x) IS_GxEPD(GxEPD2_4C_IS_, x) +#define IS_GxEPD2_7C(x) IS_GxEPD(GxEPD2_7C_IS_, x) +#define IS_GxEPD2_1248(x) IS_GxEPD(GxEPD2_1248_IS_, x) +#define IS_GxEPD2_1248c(x) IS_GxEPD(GxEPD2_1248c_IS_, x) + +#include "GxEPD2_selection_check.h" + +#if defined (ESP8266) +#define MAX_DISPLAY_BUFFER_SIZE (81920ul-34000ul-5000ul) // ~34000 base use, change 5000 to your application use +#if IS_GxEPD2_BW(GxEPD2_DISPLAY_CLASS) +#define MAX_HEIGHT(EPD) (EPD::HEIGHT <= MAX_DISPLAY_BUFFER_SIZE / (EPD::WIDTH / 8) ? EPD::HEIGHT : MAX_DISPLAY_BUFFER_SIZE / (EPD::WIDTH / 8)) +#elif IS_GxEPD2_3C(GxEPD2_DISPLAY_CLASS) || IS_GxEPD2_4C(GxEPD2_DISPLAY_CLASS) +#define MAX_HEIGHT(EPD) (EPD::HEIGHT <= (MAX_DISPLAY_BUFFER_SIZE / 2) / (EPD::WIDTH / 8) ? EPD::HEIGHT : (MAX_DISPLAY_BUFFER_SIZE / 2) / (EPD::WIDTH / 8)) +#elif IS_GxEPD2_7C(GxEPD2_DISPLAY_CLASS) +#define MAX_HEIGHT(EPD) (EPD::HEIGHT <= (MAX_DISPLAY_BUFFER_SIZE) / (EPD::WIDTH / 2) ? EPD::HEIGHT : (MAX_DISPLAY_BUFFER_SIZE) / (EPD::WIDTH / 2)) +#endif +// adapt the constructor parameters to your wiring +GxEPD2_DISPLAY_CLASS display(GxEPD2_DRIVER_CLASS(/*CS=D8*/ EPD_CS, /*DC=D3*/ 0, /*RST=D4*/ 2, /*BUSY=D2*/ 4)); +// mapping of Waveshare e-Paper ESP8266 Driver Board, new version +//GxEPD2_DISPLAY_CLASS display(GxEPD2_DRIVER_CLASS(/*CS=15*/ EPD_CS, /*DC=4*/ 4, /*RST=2*/ 2, /*BUSY=5*/ 5)); +// mapping of Waveshare e-Paper ESP8266 Driver Board, old version +//GxEPD2_DISPLAY_CLASS display(GxEPD2_DRIVER_CLASS(/*CS=15*/ EPD_CS, /*DC=4*/ 4, /*RST=5*/ 5, /*BUSY=16*/ 16)); +#undef MAX_DISPLAY_BUFFER_SIZE +#undef MAX_HEIGHT +#endif + +#if defined(ESP32) +#define MAX_DISPLAY_BUFFER_SIZE 65536ul // e.g. +#if IS_GxEPD2_BW(GxEPD2_DISPLAY_CLASS) +#define MAX_HEIGHT(EPD) (EPD::HEIGHT <= MAX_DISPLAY_BUFFER_SIZE / (EPD::WIDTH / 8) ? EPD::HEIGHT : MAX_DISPLAY_BUFFER_SIZE / (EPD::WIDTH / 8)) +#elif IS_GxEPD2_3C(GxEPD2_DISPLAY_CLASS) || IS_GxEPD2_4C(GxEPD2_DISPLAY_CLASS) +#define MAX_HEIGHT(EPD) (EPD::HEIGHT <= (MAX_DISPLAY_BUFFER_SIZE / 2) / (EPD::WIDTH / 8) ? EPD::HEIGHT : (MAX_DISPLAY_BUFFER_SIZE / 2) / (EPD::WIDTH / 8)) +#elif IS_GxEPD2_7C(GxEPD2_DISPLAY_CLASS) +#define MAX_HEIGHT(EPD) (EPD::HEIGHT <= (MAX_DISPLAY_BUFFER_SIZE) / (EPD::WIDTH / 2) ? EPD::HEIGHT : (MAX_DISPLAY_BUFFER_SIZE) / (EPD::WIDTH / 2)) +#endif +// adapt the constructor parameters to your wiring +#if !IS_GxEPD2_1248(GxEPD2_DRIVER_CLASS) && !IS_GxEPD2_1248c(GxEPD2_DRIVER_CLASS) +#if defined(ARDUINO_LOLIN_D32_PRO) +GxEPD2_DISPLAY_CLASS display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/ 15)); // my LOLIN_D32_PRO proto board +#else +//GxEPD2_DISPLAY_CLASS display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // my suggested wiring and proto board +GxEPD2_DISPLAY_CLASS display(GxEPD2_DRIVER_CLASS(/*CS=5*/ 26, /*DC=*/ 25, /*RST=*/ 33, /*BUSY=*/ 27)); // esp32 NodeMCU following AZ Delivery guide pinout +//GxEPD2_DISPLAY_CLASS display(GxEPD2_DRIVER_CLASS(/*CS=5*/ 5, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // LILYGO_T5_V2.4.1 +//GxEPD2_DISPLAY_CLASS display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 19, /*RST=*/ 4, /*BUSY=*/ 34)); // LILYGO® TTGO T5 2.66 +//GxEPD2_DISPLAY_CLASS display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 2, /*RST=*/ 0, /*BUSY=*/ 4)); // e.g. TTGO T8 ESP32-WROVER +//GxEPD2_DISPLAY_CLASS display(GxEPD2_DRIVER_CLASS(/*CS=*/ 15, /*DC=*/ 27, /*RST=*/ 26, /*BUSY=*/ 25)); // Waveshare ESP32 Driver Board +#endif +#else // GxEPD2_1248 or GxEPD2_1248c +// Waveshare 12.48 b/w or b/w/r SPI display board and frame or Good Display 12.48 b/w panel GDEW1248T3 or b/w/r panel GDEY1248Z51 +// general constructor for use with all parameters, e.g. for Waveshare ESP32 driver board mounted on connection board +GxEPD2_DISPLAY_CLASS < GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS) > display(GxEPD2_DRIVER_CLASS(/*sck=*/ 13, /*miso=*/ 12, /*mosi=*/ 14, + /*cs_m1=*/ 23, /*cs_s1=*/ 22, /*cs_m2=*/ 16, /*cs_s2=*/ 19, + /*dc1=*/ 25, /*dc2=*/ 17, /*rst1=*/ 33, /*rst2=*/ 5, + /*busy_m1=*/ 32, /*busy_s1=*/ 26, /*busy_m2=*/ 18, /*busy_s2=*/ 4)); +#endif +#undef MAX_DISPLAY_BUFFER_SIZE +#undef MAX_HEIGHT +#endif + +// can't use package "STMF1 Boards (STM32Duino.com)" (Roger Clark) anymore with Adafruit_GFX, use "STM32 Boards (selected from submenu)" (STMicroelectronics) +#if defined(ARDUINO_ARCH_STM32) +#define MAX_DISPLAY_BUFFER_SIZE 15000ul // ~15k is a good compromise +#if IS_GxEPD2_BW(GxEPD2_DISPLAY_CLASS) +#define MAX_HEIGHT(EPD) (EPD::HEIGHT <= MAX_DISPLAY_BUFFER_SIZE / (EPD::WIDTH / 8) ? EPD::HEIGHT : MAX_DISPLAY_BUFFER_SIZE / (EPD::WIDTH / 8)) +#elif IS_GxEPD2_3C(GxEPD2_DISPLAY_CLASS) || IS_GxEPD2_4C(GxEPD2_DISPLAY_CLASS) +#define MAX_HEIGHT(EPD) (EPD::HEIGHT <= (MAX_DISPLAY_BUFFER_SIZE / 2) / (EPD::WIDTH / 8) ? EPD::HEIGHT : (MAX_DISPLAY_BUFFER_SIZE / 2) / (EPD::WIDTH / 8)) +#elif IS_GxEPD2_7C(GxEPD2_DISPLAY_CLASS) +#define MAX_HEIGHT(EPD) (EPD::HEIGHT <= (MAX_DISPLAY_BUFFER_SIZE) / (EPD::WIDTH / 2) ? EPD::HEIGHT : (MAX_DISPLAY_BUFFER_SIZE) / (EPD::WIDTH / 2)) +#endif +// adapt the constructor parameters to your wiring +GxEPD2_DISPLAY_CLASS display(GxEPD2_DRIVER_CLASS(/*CS=PA4*/ EPD_CS, /*DC=*/ PA3, /*RST=*/ PA2, /*BUSY=*/ PA1)); +#undef MAX_DISPLAY_BUFFER_SIZE +#undef MAX_HEIGHT +#endif + +#if defined(__AVR) +#if defined (ARDUINO_AVR_MEGA2560) // Note: SS is on 53 on MEGA +#define MAX_DISPLAY_BUFFER_SIZE 5000 // e.g. full height for 200x200 +#else // Note: SS is on 10 on UNO, NANO +#define MAX_DISPLAY_BUFFER_SIZE 800 // +#endif +#if IS_GxEPD2_BW(GxEPD2_DISPLAY_CLASS) +#define MAX_HEIGHT(EPD) (EPD::HEIGHT <= MAX_DISPLAY_BUFFER_SIZE / (EPD::WIDTH / 8) ? EPD::HEIGHT : MAX_DISPLAY_BUFFER_SIZE / (EPD::WIDTH / 8)) +#elif IS_GxEPD2_3C(GxEPD2_DISPLAY_CLASS) || IS_GxEPD2_4C(GxEPD2_DISPLAY_CLASS) +#define MAX_HEIGHT(EPD) (EPD::HEIGHT <= (MAX_DISPLAY_BUFFER_SIZE / 2) / (EPD::WIDTH / 8) ? EPD::HEIGHT : (MAX_DISPLAY_BUFFER_SIZE / 2) / (EPD::WIDTH / 8)) +#elif IS_GxEPD2_7C(GxEPD2_DISPLAY_CLASS) +#define MAX_HEIGHT(EPD) (EPD::HEIGHT <= (MAX_DISPLAY_BUFFER_SIZE) / (EPD::WIDTH / 2) ? EPD::HEIGHT : (MAX_DISPLAY_BUFFER_SIZE) / (EPD::WIDTH / 2)) +#endif +// adapt the constructor parameters to your wiring +GxEPD2_DISPLAY_CLASS display(GxEPD2_DRIVER_CLASS(/*CS=*/ EPD_CS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); +// for Arduino Micro or Arduino Leonardo with CS on 10 on my proto boards (SS would be 17) uncomment instead: +//GxEPD2_DISPLAY_CLASS display(GxEPD2_DRIVER_CLASS(/*CS=*/ 10, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); +#endif + +#if defined(ARDUINO_ARCH_SAM) +#define MAX_DISPLAY_BUFFER_SIZE 32768ul // e.g., up to 96k +#if IS_GxEPD2_BW(GxEPD2_DISPLAY_CLASS) +#define MAX_HEIGHT(EPD) (EPD::HEIGHT <= MAX_DISPLAY_BUFFER_SIZE / (EPD::WIDTH / 8) ? EPD::HEIGHT : MAX_DISPLAY_BUFFER_SIZE / (EPD::WIDTH / 8)) +#elif IS_GxEPD2_3C(GxEPD2_DISPLAY_CLASS) || IS_GxEPD2_4C(GxEPD2_DISPLAY_CLASS) +#define MAX_HEIGHT(EPD) (EPD::HEIGHT <= (MAX_DISPLAY_BUFFER_SIZE / 2) / (EPD::WIDTH / 8) ? EPD::HEIGHT : (MAX_DISPLAY_BUFFER_SIZE / 2) / (EPD::WIDTH / 8)) +#elif IS_GxEPD2_7C(GxEPD2_DISPLAY_CLASS) +#define MAX_HEIGHT(EPD) (EPD::HEIGHT <= (MAX_DISPLAY_BUFFER_SIZE) / (EPD::WIDTH / 2) ? EPD::HEIGHT : (MAX_DISPLAY_BUFFER_SIZE) / (EPD::WIDTH / 2)) +#endif +// adapt the constructor parameters to your wiring +GxEPD2_DISPLAY_CLASS display(GxEPD2_DRIVER_CLASS(/*CS=10*/ EPD_CS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); +#undef MAX_DISPLAY_BUFFER_SIZE +#undef MAX_HEIGHT +#endif + +#if defined(ARDUINO_ARCH_SAMD) +#define MAX_DISPLAY_BUFFER_SIZE 15000ul // ~15k is a good compromise +#if IS_GxEPD2_BW(GxEPD2_DISPLAY_CLASS) +#define MAX_HEIGHT(EPD) (EPD::HEIGHT <= MAX_DISPLAY_BUFFER_SIZE / (EPD::WIDTH / 8) ? EPD::HEIGHT : MAX_DISPLAY_BUFFER_SIZE / (EPD::WIDTH / 8)) +#elif IS_GxEPD2_3C(GxEPD2_DISPLAY_CLASS) || IS_GxEPD2_4C(GxEPD2_DISPLAY_CLASS) +#define MAX_HEIGHT(EPD) (EPD::HEIGHT <= (MAX_DISPLAY_BUFFER_SIZE / 2) / (EPD::WIDTH / 8) ? EPD::HEIGHT : (MAX_DISPLAY_BUFFER_SIZE / 2) / (EPD::WIDTH / 8)) +#elif IS_GxEPD2_7C(GxEPD2_DISPLAY_CLASS) +#define MAX_HEIGHT(EPD) (EPD::HEIGHT <= (MAX_DISPLAY_BUFFER_SIZE) / (EPD::WIDTH / 2) ? EPD::HEIGHT : (MAX_DISPLAY_BUFFER_SIZE) / (EPD::WIDTH / 2)) +#endif +// adapt the constructor parameters to your wiring +GxEPD2_DISPLAY_CLASS display(GxEPD2_DRIVER_CLASS(/*CS=4*/ 4, /*DC=*/ 7, /*RST=*/ 6, /*BUSY=*/ 5)); +//GxEPD2_DISPLAY_CLASS display(GxEPD2_DRIVER_CLASS(/*CS=4*/ 4, /*DC=*/ 3, /*RST=*/ 2, /*BUSY=*/ 1)); // my Seed XIOA0 +//GxEPD2_DISPLAY_CLASS display(GxEPD2_DRIVER_CLASS(/*CS=4*/ 3, /*DC=*/ 2, /*RST=*/ 1, /*BUSY=*/ 0)); // my other Seed XIOA0 +#undef MAX_DISPLAY_BUFFER_SIZE +#undef MAX_HEIGHT +#endif + +#if defined(ARDUINO_ARCH_RP2040) +#define MAX_DISPLAY_BUFFER_SIZE 131072ul // e.g. half of available ram +#if IS_GxEPD2_BW(GxEPD2_DISPLAY_CLASS) +#define MAX_HEIGHT(EPD) (EPD::HEIGHT <= MAX_DISPLAY_BUFFER_SIZE / (EPD::WIDTH / 8) ? EPD::HEIGHT : MAX_DISPLAY_BUFFER_SIZE / (EPD::WIDTH / 8)) +#elif IS_GxEPD2_3C(GxEPD2_DISPLAY_CLASS) || IS_GxEPD2_4C(GxEPD2_DISPLAY_CLASS) +#define MAX_HEIGHT(EPD) (EPD::HEIGHT <= (MAX_DISPLAY_BUFFER_SIZE / 2) / (EPD::WIDTH / 8) ? EPD::HEIGHT : (MAX_DISPLAY_BUFFER_SIZE / 2) / (EPD::WIDTH / 8)) +#elif IS_GxEPD2_7C(GxEPD2_DISPLAY_CLASS) +#define MAX_HEIGHT(EPD) (EPD::HEIGHT <= (MAX_DISPLAY_BUFFER_SIZE) / (EPD::WIDTH / 2) ? EPD::HEIGHT : (MAX_DISPLAY_BUFFER_SIZE) / (EPD::WIDTH / 2)) +#endif +#if defined(ARDUINO_NANO_RP2040_CONNECT) +// adapt the constructor parameters to your wiring +GxEPD2_DISPLAY_CLASS display(GxEPD2_DRIVER_CLASS(/*CS=*/ EPD_CS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); +#endif +#if defined(ARDUINO_RASPBERRY_PI_PICO) +// adapt the constructor parameters to your wiring +//GxEPD2_DISPLAY_CLASS display(GxEPD2_DRIVER_CLASS(/*CS=*/ EPD_CS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); // my proto board +// mapping of GoodDisplay DESPI-PICO. NOTE: uses alternate HW SPI pins! +GxEPD2_DISPLAY_CLASS display(GxEPD2_DRIVER_CLASS(/*CS=*/ 3, /*DC=*/ 2, /*RST=*/ 1, /*BUSY=*/ 0)); // DESPI-PICO +//GxEPD2_DISPLAY_CLASS display(GxEPD2_DRIVER_CLASS(/*CS=*/ 3, /*DC=*/ 2, /*RST=*/ 11, /*BUSY=*/ 10)); // DESPI-PICO modified +#endif +#undef MAX_DISPLAY_BUFFER_SIZE +#undef MAX_HEIGHT +#endif + +#endif diff --git a/include/GxEPD2_selection_check.h b/include/GxEPD2_selection_check.h new file mode 100644 index 0000000..df552f0 --- /dev/null +++ b/include/GxEPD2_selection_check.h @@ -0,0 +1,106 @@ +// Display Library example for SPI e-paper panels from Dalian Good Display and boards from Waveshare. +// Requires HW SPI and Adafruit_GFX. Caution: the e-paper panels require 3.3V supply AND data lines! +// +// Display Library based on Demo Example from Good Display: http://www.e-paper-display.com/download_list/downloadcategoryid=34&isMode=false.html +// +// Author: Jean-Marc Zingg +// +// Version: see library.properties +// +// Library: https://github.com/ZinggJM/GxEPD2 + +// Supporting Arduino Forum Topics: +// Waveshare e-paper displays with SPI: http://forum.arduino.cc/index.php?topic=487007.0 +// Good Display ePaper for Arduino: https://forum.arduino.cc/index.php?topic=436411.0 + +#define GxEPD2_102_IS_BW true +#define GxEPD2_150_BN_IS_BW true +#define GxEPD2_154_IS_BW true +#define GxEPD2_154_D67_IS_BW true +#define GxEPD2_154_T8_IS_BW true +#define GxEPD2_154_M09_IS_BW true +#define GxEPD2_154_M10_IS_BW true +#define GxEPD2_154_GDEY0154D67_IS_BW true +#define GxEPD2_213_IS_BW true +#define GxEPD2_213_B72_IS_BW true +#define GxEPD2_213_B73_IS_BW true +#define GxEPD2_213_B74_IS_BW true +#define GxEPD2_213_flex_IS_BW true +#define GxEPD2_213_M21_IS_BW true +#define GxEPD2_213_T5D_IS_BW true +#define GxEPD2_213_BN_IS_BW true +#define GxEPD2_213_GDEY0213B74_IS_BW true +#define GxEPD2_260_IS_BW true +#define GxEPD2_260_M01_IS_BW true +#define GxEPD2_266_BN_IS_BW true +#define GxEPD2_266_GDEY0266T90_IS_BW true +#define GxEPD2_270_IS_BW true +#define GxEPD2_270_GDEY027T91_IS_BW true +#define GxEPD2_290_IS_BW true +#define GxEPD2_290_T5_IS_BW true +#define GxEPD2_290_T5D_IS_BW true +#define GxEPD2_290_I6FD_IS_BW true +#define GxEPD2_290_T94_IS_BW true +#define GxEPD2_290_T94_V2_IS_BW true +#define GxEPD2_290_BS_IS_BW true +#define GxEPD2_290_M06_IS_BW true +#define GxEPD2_290_GDEY029T94_IS_BW true +#define GxEPD2_371_IS_BW true +#define GxEPD2_370_TC1_IS_BW true +#define GxEPD2_420_IS_BW true +#define GxEPD2_420_M01_IS_BW true +#define GxEPD2_420_GDEY042T91_IS_BW true +#define GxEPD2_583_IS_BW true +#define GxEPD2_583_T8_IS_BW true +#define GxEPD2_583_GDEQ0583T31_IS_BW true +#define GxEPD2_750_IS_BW true +#define GxEPD2_750_T7_IS_BW true +#define GxEPD2_750_YT7_IS_BW true +#define GxEPD2_1160_T91_IS_BW true +#define GxEPD2_1248_IS_BW true +#define GxEPD2_it60_IS_BW true +#define GxEPD2_it60_1448x1072_IS_BW true +#define GxEPD2_it78_1872x1404_IS_BW true +#define GxEPD2_it103_1872x1404_IS_BW true +// 3-color e-papers +#define GxEPD2_154c_IS_3C true +#define GxEPD2_154_Z90c_IS_3C true +#define GxEPD2_213c_IS_3C true +#define GxEPD2_213_Z19c_IS_3C true +#define GxEPD2_213_Z98c_IS_3C true +#define GxEPD2_266c_IS_3C true +#define GxEPD2_270c_IS_3C true +#define GxEPD2_290c_IS_3C true +#define GxEPD2_290_Z13c_IS_3C true +#define GxEPD2_290_C90c_IS_3C true +#define GxEPD2_420c_IS_3C true +#define GxEPD2_420c_Z21_IS_3C true +#define GxEPD2_583c_IS_3C true +#define GxEPD2_583c_Z83_IS_3C true +#define GxEPD2_750c_IS_3C true +#define GxEPD2_750c_Z08_IS_3C true +#define GxEPD2_750c_Z90_IS_3C true +#define GxEPD2_1248c_IS_3C true +// 4-color e-paper +#define GxEPD2_437c_IS_4C true +// 7-color e-paper +#define GxEPD2_565c_IS_7C true +#define GxEPD2_730c_GDEY073D46_IS_7C true + +#if defined(GxEPD2_DISPLAY_CLASS) && defined(GxEPD2_DRIVER_CLASS) +#define IS_GxEPD2_DRIVER(c, x) (c##x) +#define IS_GxEPD2_DRIVER_BW(x) IS_GxEPD2_DRIVER(x, _IS_BW) +#define IS_GxEPD2_DRIVER_3C(x) IS_GxEPD2_DRIVER(x, _IS_3C) +#define IS_GxEPD2_DRIVER_4C(x) IS_GxEPD2_DRIVER(x, _IS_4C) +#define IS_GxEPD2_DRIVER_7C(x) IS_GxEPD2_DRIVER(x, _IS_7C) +#if IS_GxEPD2_BW(GxEPD2_DISPLAY_CLASS) && IS_GxEPD2_DRIVER_3C(GxEPD2_DRIVER_CLASS) +#error "GxEPD2_BW used with 3-color driver class" +#endif +#if IS_GxEPD2_3C(GxEPD2_DISPLAY_CLASS) && IS_GxEPD2_DRIVER_BW(GxEPD2_DRIVER_CLASS) +#error "GxEPD2_3C used with b/w driver class" +#endif +#if !IS_GxEPD2_DRIVER_BW(GxEPD2_DRIVER_CLASS) && !IS_GxEPD2_DRIVER_3C(GxEPD2_DRIVER_CLASS) && !IS_GxEPD2_DRIVER_4C(GxEPD2_DRIVER_CLASS) && !IS_GxEPD2_DRIVER_7C(GxEPD2_DRIVER_CLASS) +#error "neither BW nor 3C nor 4C nor 7C kind defined for driver class (error in GxEPD2_selection_check.h)" +#endif + +#endif diff --git a/include/GxEPD2_wiring_examples.h b/include/GxEPD2_wiring_examples.h new file mode 100644 index 0000000..97ab896 --- /dev/null +++ b/include/GxEPD2_wiring_examples.h @@ -0,0 +1,83 @@ +// Display Library example for SPI e-paper panels from Dalian Good Display and boards from Waveshare. +// Requires HW SPI and Adafruit_GFX. Caution: the e-paper panels require 3.3V supply AND data lines! +// +// Display Library based on Demo Example from Good Display: http://www.e-paper-display.com/download_list/downloadcategoryid=34&isMode=false.html +// +// Author: Jean-Marc Zingg +// +// Version: see library.properties +// +// Library: https://github.com/ZinggJM/GxEPD2 + +// Supporting Arduino Forum Topics: +// Waveshare e-paper displays with SPI: http://forum.arduino.cc/index.php?topic=487007.0 +// Good Display ePaper for Arduino: https://forum.arduino.cc/index.php?topic=436411.0 + +// mapping suggestion from Waveshare SPI e-Paper to Wemos D1 mini +// BUSY -> D2, RST -> D4, DC -> D3, CS -> D8, CLK -> D5, DIN -> D7, GND -> GND, 3.3V -> 3.3V +// NOTE: connect 3.3k pull-down from D8 to GND if your board or shield has level converters +// NOTE for ESP8266: using SS (GPIO15) for CS may cause boot mode problems, use different pin in case, or 4k7 pull-down +// NOTE: connect 1k pull-up from D4 (RST) to 3.3V if your board or shield has the "clever" reset circuit, or use a different pin + +// mapping suggestion from Waveshare SPI e-Paper to generic ESP8266 +// BUSY -> GPIO4, RST -> GPIO2, DC -> GPIO0, CS -> GPIO15, CLK -> GPIO14, DIN -> GPIO13, GND -> GND, 3.3V -> 3.3V +// NOTE: connect 3.3k pull-down from GPIO15 to GND if your board or shield has level converters +// NOTE for ESP8266: using SS (GPIO15) for CS may cause boot mode problems, use different pin in case, or 3.3k pull-down +// NOTE: connect 1k pull-up from GPIO2 (RST) to 3.3V if your board or shield has the "clever" reset circuit, or use a different pin + +// mapping of Waveshare e-Paper ESP8266 Driver Board, new version +// BUSY -> GPIO5, RST -> GPIO2, DC -> GPIO4, CS -> GPIO15, CLK -> GPIO14, DIN -> GPIO13, GND -> GND, 3.3V -> 3.3V +// NOTE for ESP8266: using SS (GPIO15) for CS may cause boot mode problems, add a 3.3k pull-down in case +// the e-Paper ESP8266 Driver Board should have no boot mode issue, as it doesn't use level converters + +// mapping of Waveshare e-Paper ESP8266 Driver Board, old version +// BUSY -> GPIO16, RST -> GPIO5, DC -> GPIO4, CS -> GPIO15, CLK -> GPIO14, DIN -> GPIO13, GND -> GND, 3.3V -> 3.3V +// NOTE for ESP8266: using SS (GPIO15) for CS may cause boot mode problems, add a 3.3k pull-down in case +// the e-Paper ESP8266 Driver Board should have no boot mode issue, as it doesn't use level converters + +// mapping suggestion for ESP32, e.g. LOLIN32, see .../variants/.../pins_arduino.h for your board +// NOTE: there are variants with different pins for SPI ! CHECK SPI PINS OF YOUR BOARD +// BUSY -> 4, RST -> 16, DC -> 17, CS -> SS(5), CLK -> SCK(18), DIN -> MOSI(23), GND -> GND, 3.3V -> 3.3V + +// mapping of Waveshare ESP32 Driver Board +// BUSY -> 25, RST -> 26, DC -> 27, CS-> 15, CLK -> 13, DIN -> 14 +// NOTE: this board uses "unusual" SPI pins and requires re-mapping of HW SPI to these pins in SPIClass +// see example GxEPD2_WS_ESP32_Driver.ino, it shows how this can be done easily + +// mapping suggestion for ESP32, e.g. LOLIN32 D32 PRO +// BUSY -> 15, RST -> 2, DC -> 0, CS -> 5, CLK -> SCK(18), DIN -> MOSI(23), GND -> GND, 3.3V -> 3.3V +// note: use explicit value for CS, as SS is re-defined to TF_CS(4) in pins_arduino.h for Board: "LOLIN D32 PRO" + +// mapping suggestion for ESP32, e.g. TTGO T8 ESP32-WROVER +// BUSY -> 4, RST -> 0, DC -> 2, CS -> SS(5), CLK -> SCK(18), DIN -> MOSI(23), GND -> GND, 3.3V -> 3.3V +// for use with Board: "ESP32 Dev Module": + +// new mapping suggestion for STM32F1, e.g. STM32F103C8T6 "BluePill" +// BUSY -> A1, RST -> A2, DC -> A3, CS-> A4, CLK -> A5, DIN -> A7 + +// mapping suggestion for AVR, UNO, NANO etc. +// BUSY -> 7, RST -> 9, DC -> 8, CS-> 10, CLK -> 13, DIN -> 11 + +// mapping suggestion for AVR, Arduino Micro, Leonardo +// note: on Leonardo board HW SPI pins are on 6-pin ICSP header +// BUSY -> 7, RST -> 9, DC -> 8, CS-> 10, CLK -> 15, DIN -> 16 + +// mapping of Waveshare Universal e-Paper Raw Panel Driver Shield for Arduino / NUCLEO +// BUSY -> 7, RST -> 8, DC -> 9, CS-> 10, CLK -> 13, DIN -> 11 + +// mapping suggestion for Arduino MEGA +// BUSY -> 7, RST -> 9, DC -> 8, CS-> 53, CLK -> 52, DIN -> 51 + +// mapping suggestion for Arduino DUE, note: pin 77 is on board pin 10, SS is 10 +// BUSY -> 7, RST -> 9, DC -> 8, CS-> 10, CLK -> 76, DIN -> 75 +// SPI pins are on 6 pin 2x3 SPI header, no SS on SPI header! + +// mapping suggestion for Arduino MKR1000 or MKRZERO +// note: can't use SS on MKR1000: is defined as 24, should be 4 +// BUSY -> 5, RST -> 6, DC -> 7, CS-> 4, CLK -> 9, DIN -> 8 + +// mapping suggestion for Arduino Nano RP2040 Connect +// BUSY -> 7, RST -> 9, DC -> 8, CS-> 10, CLK -> 13, DIN -> 11 + +// mapping suggestion for Raspberry Pi Pico RP2040 +// BUSY -> 7, RST -> 9, DC -> 8, CS-> 5, CLK -> 2, DIN -> 3 diff --git a/include/README b/include/README new file mode 100644 index 0000000..194dcd4 --- /dev/null +++ b/include/README @@ -0,0 +1,39 @@ + +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 usual convention is to give header files names that end with `.h'. +It is most portable to use only letters, digits, dashes, and underscores in +header file names, and at most one dot. + +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/include/lightning_atm.h b/include/lightning_atm.h new file mode 100644 index 0000000..39c106f --- /dev/null +++ b/include/lightning_atm.h @@ -0,0 +1,50 @@ +#ifndef LIGHTNING_ATM_H +# define LIGHTNING_ATM_H + +#include +#include +#include +#include "bitmaps/Bitmaps200x200.h" +#include "qrcode.h" +#include "Bitcoin.h" +#include +#include +#include + +// select the display class and display driver class in the following file (new style): +#include "GxEPD2_display_selection_new_style.h" + +//Generate the URL and secret in LNBITS with the LNURLDevice Extension: +String baseURLATM = "https://legend.lnbits.com/lnurldevice/api/v1/lnurl/234i8"; +String secretATM = "d4RQVjJZQ7ubqvLfLQHCvk"; +String currencyATM = "EUR"; + +#define COIN_PIN 17 +#define PULSE_TIMEOUT 200 +#define LED_BUTTON_PIN 13 +#define BUTTON_PIN 32 +#define MOSFET_PIN 12 + +typedef struct s_qrdata { + uint8_t current_y; + uint8_t current_x; + uint8_t start_x; + uint8_t start_y; + uint8_t module_size; + uint8_t qr_size; +} t_qrdata; + +// put function declarations here: +void clean_screen(); +void to_upper(char *arr); +void qr_withdrawl_screen(String top_message, String bottom_message, const char *qr_content); +char *makeLNURL(float total); +int xor_encrypt(uint8_t *output, size_t outlen, uint8_t *key, size_t keylen, uint8_t *nonce, size_t nonce_len, uint64_t pin, uint64_t amount_in_cents); +void show_inserted_amount(int amount_in_cents); +String get_amount_string(int amount_in_cents); +unsigned int detect_coin(); +void home_screen(); +void IRAM_ATTR button_pressed_itr(); +void wait_for_user_to_scan(); + +#endif diff --git a/lib/README b/lib/README new file mode 100644 index 0000000..6debab1 --- /dev/null +++ b/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 executable file. + +The source code of each library should be placed in a an own separate directory +("lib/your_library_name/[here are source files]"). + +For example, see a structure of the following two libraries `Foo` and `Bar`: + +|--lib +| | +| |--Bar +| | |--docs +| | |--examples +| | |--src +| | |- Bar.c +| | |- Bar.h +| | |- library.json (optional, 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 + +and a contents of `src/main.c`: +``` +#include +#include + +int main (void) +{ + ... +} + +``` + +PlatformIO Library Dependency Finder will find automatically dependent +libraries scanning project source files. + +More information about PlatformIO Library Dependency Finder +- https://docs.platformio.org/page/librarymanager/ldf.html diff --git a/platformio.ini b/platformio.ini new file mode 100644 index 0000000..aaeecc5 --- /dev/null +++ b/platformio.ini @@ -0,0 +1,19 @@ +; 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] +platform = espressif32 +board = esp32dev +framework = arduino +monitor_speed = 9600 +lib_deps = + zinggjm/GxEPD2@^1.5.2 + ricmoo/QRCode@^0.0.1 + stepansnigirev/uBitcoin@^0.2.0 diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..8cedb18 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,357 @@ +#include "lightning_atm.h" + +const unsigned int COINS[] = {0, 0, 5, 10, 20, 50, 100, 200}; +bool button_pressed = false; +unsigned int inserted_cents = 0; +unsigned long long time_last_press = millis(); + +void setup() +{ + display.init(115200, true, 2, false); + Serial.begin(9600); + pinMode(COIN_PIN, INPUT_PULLUP); + pinMode(LED_BUTTON_PIN, OUTPUT); + pinMode(BUTTON_PIN, INPUT_PULLUP); + pinMode(MOSFET_PIN, OUTPUT); + digitalWrite(MOSFET_PIN, LOW); + attachInterrupt(BUTTON_PIN, button_pressed_itr, FALLING); + home_screen(); + digitalWrite(LED_BUTTON_PIN, HIGH); +} + +void loop() { + unsigned int pulses = 0; + unsigned long long time_last_press; + + pulses = detect_coin(); + if (pulses >= 2 && pulses <= 7) + { + digitalWrite(MOSFET_PIN, HIGH); + digitalWrite(LED_BUTTON_PIN, LOW); + inserted_cents += COINS[pulses]; + show_inserted_amount(inserted_cents); + display.hibernate(); + delay(100); + } + else if (button_pressed && inserted_cents > 0) + { + digitalWrite(MOSFET_PIN, HIGH); + button_pressed = false; + char *lnurl = makeLNURL(inserted_cents); + qr_withdrawl_screen("Please scan this LNURLW QR code:", "Then press the \nbutton to finish", lnurl); + free(lnurl); + wait_for_user_to_scan(); + digitalWrite(LED_BUTTON_PIN, HIGH); + home_screen(); + digitalWrite(MOSFET_PIN, LOW); + inserted_cents = 0; + } + else if (button_pressed && !pulses && !inserted_cents) + { + int press_counter = 0; + + button_pressed = false; + time_last_press = millis(); + while ((millis() - time_last_press) < 5000 && press_counter < 6) + { + if (button_pressed) + { + time_last_press = millis(); + button_pressed = false; + press_counter++; + delay(600); + } + } + if (press_counter > 5) + { + digitalWrite(LED_BUTTON_PIN, LOW); + clean_screen(); + display.hibernate(); + while ((millis() - time_last_press) < 30000) + delay(1000); + home_screen(); + } + } +} + +void IRAM_ATTR button_pressed_itr() { + button_pressed = true; +} + +void wait_for_user_to_scan() +{ + unsigned long long time; + bool light_on; + + light_on = true; + time = millis(); + button_pressed = false; + while (!button_pressed && (millis() - time) < 600000) + { + if (!light_on) + { + digitalWrite(LED_BUTTON_PIN, HIGH); + light_on = true; + } + else if (light_on) + { + digitalWrite(LED_BUTTON_PIN, LOW); + light_on = false; + } + delay(500); + } +} + +unsigned int detect_coin() +{ + unsigned long last_pulse; + unsigned int pulses; + bool prev_value; + bool read_value; + + pulses = 0; + read_value = 1; + prev_value = digitalRead(COIN_PIN); + digitalWrite(LED_BUTTON_PIN, HIGH); + digitalWrite(MOSFET_PIN, LOW); + button_pressed = false; + while (true && !button_pressed) + { + read_value = digitalRead(COIN_PIN); + if (read_value != prev_value && !read_value) + { + pulses++; + last_pulse = millis(); + } + prev_value = read_value; + if (pulses > 0 && (millis() - last_pulse > PULSE_TIMEOUT)) + { + break; + } + } + if (button_pressed) + return (0); + Serial.println("Returned coin detector"); + Serial.println(pulses); + return (pulses); +} + +/* +** DISPLAY UTILS +*/ +void home_screen() +{ + display.setRotation(1); + display.setFullWindow(); + display.firstPage(); + + display.setCursor(0, 10); + display.setTextSize(3); + display.setTextColor(GxEPD_BLACK, GxEPD_WHITE); + display.println("Insert\nEuro coins\non the\nright\nside to\nstart ->"); + + display.setCursor(0, 160); + display.setTextSize(1); + display.setTextColor(GxEPD_BLACK, GxEPD_WHITE); + display.println("Prepare Lightning enabled Bitcoin\nwallet before starting!\nSupported coins: 5ct, 10ct, \n20ct, 50ct, 1eur, 2eur"); + display.nextPage(); + display.hibernate(); +} + +void show_inserted_amount(int amount_in_cents) +{ + String amount_in_euro; + + display.setRotation(1); + display.setFullWindow(); + display.firstPage(); + + display.setCursor(0, 4); + display.setTextSize(2); + display.setTextColor(GxEPD_BLACK, GxEPD_WHITE); + display.println("Inserted amount:"); + + amount_in_euro = get_amount_string(amount_in_cents); + display.setCursor(10, 90); + display.setTextSize(3); + display.setTextColor(GxEPD_BLACK, GxEPD_WHITE); + display.println(amount_in_euro); + + display.setCursor(0, 160); + display.setTextSize(2); + display.setTextColor(GxEPD_BLACK, GxEPD_WHITE); + display.println(" Press button\n once finished."); + + display.nextPage(); + display.hibernate(); +} + +void qr_withdrawl_screen(String top_message, String bottom_message, const char *qr_content) +{ + QRCode qrcoded; + uint8_t qrcodeData[qrcode_getBufferSize(20)]; // 20 is "qr version" + t_qrdata qr; + + qrcode_initText(&qrcoded, qrcodeData, 11, 0, qr_content); + qr.qr_size = qrcoded.size * 2; + qr.start_x = (200 - qr.qr_size) / 2; + qr.start_y = (200 - qr.qr_size) / 2; + qr.module_size = 2; + + display.setRotation(1); + display.setFullWindow(); + display.firstPage(); + for (qr.current_y = 0; qr.current_y < qrcoded.size; qr.current_y++) + { + for (qr.current_x = 0; qr.current_x < qrcoded.size; qr.current_x++) + { + if (qrcode_getModule(&qrcoded, qr.current_x, qr.current_y)) + display.fillRect(qr.start_x + qr.module_size * qr.current_x, + qr.start_y + qr.module_size * qr.current_y, qr.module_size, qr.module_size, GxEPD_BLACK); + else + display.fillRect(qr.start_x + qr.module_size * qr.current_x, + qr.start_y + qr.module_size * qr.current_y, qr.module_size, qr.module_size, GxEPD_WHITE); + } + } + display.setCursor(0, 4); + display.setTextSize(2); + display.setTextColor(GxEPD_BLACK, GxEPD_WHITE); + display.println(top_message); + display.setCursor(0, 170); + display.setTextSize(2); + display.setTextColor(GxEPD_BLACK, GxEPD_WHITE); + display.println(bottom_message); + display.nextPage(); + // display.hibernate(); +} + +String get_amount_string(int amount_in_cents) +{ + String euro; + String cents; + String return_value; + int euro_value; + int cent_remainder; + + euro_value = amount_in_cents / 100; + cent_remainder = amount_in_cents % 100; + euro = String(euro_value); + cents = String(cent_remainder); + return_value = String(euro + '.' + cents + " Euro"); + return (return_value); +} + + +/* +** Called to clean the e-ink screen for storage over longer periods +*/ +void clean_screen() +{ + display.firstPage(); + display.nextPage(); + display.hibernate(); +} + +//////////////////////////////////////////// +///////////////LNURL STUFF////////////////// +////USING STEPAN SNIGREVS GREAT CRYTPO////// +////////////THANK YOU STEPAN//////////////// +//////////////////////////////////////////// + +int xor_encrypt(uint8_t *output, size_t outlen, uint8_t *key, size_t keylen, uint8_t *nonce, size_t nonce_len, uint64_t pin, uint64_t amount_in_cents) +{ + // check we have space for all the data: + // + if (outlen < 2 + nonce_len + 1 + lenVarInt(pin) + 1 + lenVarInt(amount_in_cents) + 8) + { + return 0; + } + + int cur = 0; + output[cur] = 1; // variant: XOR encryption + cur++; + + // nonce_len | nonce + output[cur] = nonce_len; + cur++; + memcpy(output + cur, nonce, nonce_len); + cur += nonce_len; + + // payload, unxored first - + int payload_len = lenVarInt(pin) + 1 + lenVarInt(amount_in_cents); + output[cur] = (uint8_t)payload_len; + cur++; + uint8_t *payload = output + cur; // pointer to the start of the payload + cur += writeVarInt(pin, output + cur, outlen - cur); // pin code + cur += writeVarInt(amount_in_cents, output + cur, outlen - cur); // amount + cur++; + + // xor it with round key + uint8_t hmacresult[32]; + SHA256 h; + h.beginHMAC(key, keylen); + h.write((uint8_t *) "Round secret:", 13); + h.write(nonce, nonce_len); + h.endHMAC(hmacresult); + for (int i = 0; i < payload_len; i++) + { + payload[i] = payload[i] ^ hmacresult[i]; + } + + // add hmac to authenticate + h.beginHMAC(key, keylen); + h.write((uint8_t *) "Data:", 5); + h.write(output, cur); + h.endHMAC(hmacresult); + memcpy(output + cur, hmacresult, 8); + cur += 8; + + // return number of bytes written to the output + return cur; +} + +char *makeLNURL(float total) +{ + int randomPin = random(1000, 9999); + byte nonce[8]; + for (int i = 0; i < 8; i++) + { + nonce[i] = random(256); + } + byte payload[51]; // 51 bytes is max one can get with xor-encryption + + size_t payload_len = xor_encrypt(payload, sizeof(payload), (uint8_t *)secretATM.c_str(), secretATM.length(), nonce, sizeof(nonce), randomPin, float(total)); + String preparedURL = baseURLATM + "?atm=1&p="; + preparedURL += toBase64(payload, payload_len, BASE64_URLSAFE | BASE64_NOPADDING); + + Serial.println(preparedURL); + char Buf[200]; + preparedURL.toCharArray(Buf, 200); + char *url = Buf; + byte *data = (byte *)calloc(strlen(url) * 2, sizeof(byte)); + if (!data) + return (NULL); + size_t len = 0; + int res = convert_bits(data, &len, 5, (byte *) url, strlen(url), 8, 1); + char *charLnurl = (char *) calloc(strlen(url) * 2, sizeof(byte)); + if (!charLnurl) + { + free(data); + return (NULL); + } + bech32_encode(charLnurl, "lnurl", data, len); + to_upper(charLnurl); + free(data); + return (charLnurl); +} + +void to_upper(char *arr) +{ + for (size_t i = 0; i < strlen(arr); i++) + { + if (arr[i] >= 'a' && arr[i] <= 'z') + { + arr[i] = arr[i] - 'a' + 'A'; + } + } +} diff --git a/test/README b/test/README new file mode 100644 index 0000000..9b1e87b --- /dev/null +++ b/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