a first version of a modular structur of the code based on a few classes, Acceptor and eInk and Button are working

This commit is contained in:
Jens Noack 2025-02-21 21:42:34 +01:00
parent 493642aa90
commit b15cf8d365
12 changed files with 589 additions and 1365 deletions

View file

@ -1,289 +0,0 @@
// 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
// *** for Waveshare ESP32 Driver board *** //
// mapping of Waveshare ESP32 Driver Board
// BUSY -> 25, RST -> 26, DC -> 27, CS-> 15, CLK -> 13, DIN -> 14
// uncomment next two lines for Waveshare ESP32 Driver Board
// #define USE_HSPI_FOR_EPD
// #define ENABLE_GxEPD2_GFX 0
// *** end Waveshare ESP32 Driver board *** //
// 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_150_BN // 1.54 inch Waveshare e-paper display
const String display_type = "GxEPD2_150_BN";
// #define GxEPD2_DRIVER_CLASS GxEPD2_213_B74 // Waveshare 2.13 inch e-paper display - Version 3
// const String display_type = "GxEPD2_213_B74";
// #define GxEPD2_DRIVER_CLASS GxEPD2_213_flex // Waveshare 2.13 inch e-paper display - (D) flex (yellow)
// const String display_type = "GxEPD2_213_flex";
// #define GxEPD2_DRIVER_CLASS GxEPD2_270 // Waveshare 264x176, 2.7inch E-Ink display - Version 1
// const String display_type = "GxEPD2_270";
// #define GxEPD2_DRIVER_CLASS GxEPD2_270_GDEY027T91 // Waveshare 264x176, 2.7inch E-Ink display - Version 2
// const String display_type = "GxEPD2_270_GDEY027T91";
// #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_102 // GDEW0102T4 80x128, UC8175, (WFT0102CZA2)
// #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)
// #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_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<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_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<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_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<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_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<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_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<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // my suggested wiring and proto board
// *** uncomment next line for standard ESP32 *** //
// GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ 26, /*DC=*/25, /*RST=*/33, /*BUSY=*/27)); // esp32 NodeMCU following AZ Delivery guide pinout
// GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ 5, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // LILYGO_T5_V2.4.1
// GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 19, /*RST=*/ 4, /*BUSY=*/ 34)); // LILYGO® TTGO T5 2.66
// GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 2, /*RST=*/ 0, /*BUSY=*/ 4)); // e.g. TTGO T8 ESP32-WROVER
// *** uncomment next line for Waveshare ESP32 Driver board *** //
GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_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<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_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<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_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<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_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<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_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<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=4*/ 4, /*DC=*/7, /*RST=*/6, /*BUSY=*/5));
// GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=4*/ 4, /*DC=*/ 3, /*RST=*/ 2, /*BUSY=*/ 1)); // my Seed XIOA0
// GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_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<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_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<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_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<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=*/3, /*DC=*/2, /*RST=*/1, /*BUSY=*/0)); // DESPI-PICO
// GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_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

View file

@ -1,106 +0,0 @@
// 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

View file

@ -1,83 +0,0 @@
// 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

36
firmware/include/button.h Normal file
View file

@ -0,0 +1,36 @@
#ifndef ATMBUTTON_H
#define ATMBUTTON_H
#include <Arduino.h>
class AtmButton {
private:
uint8_t pin, ledPin;
uint8_t ledState = LEDOFF;
volatile bool pressed = false;
volatile unsigned long last_pressed_ms = 0;
volatile unsigned long pressed_at_ms = 0;
volatile unsigned long pressed_after_ms = 0;
bool activeWaiting = false;
unsigned long startWaitTime = 0;
unsigned long lastWaitLedToggle = 0;
static void IRAM_ATTR buttonIsrHandler(void* arg); // Interrupt Service Routine (ISR)
public:
const uint8_t LEDON = HIGH;
const uint8_t LEDOFF = LOW;
const unsigned long DEBOUNCE_BUTTON_MS = 200; // wait that number of ms before counting the button pressed pulse -> debouncing
AtmButton(uint8_t, uint8_t );
void begin();
bool wasPressed();
void ledOn();
void ledOff();
void ledToggle();
bool iswaitingUntilPressed(unsigned long maxTimeToWaitMs, unsigned long blinkPeriodMs);
};
#endif

View file

@ -0,0 +1,36 @@
#ifndef COINACCEPTOR_H
#define COINACCEPTOR_H
#include "Arduino.h"
class CoinAcceptor {
private:
uint8_t pulsePin, enablePin;
uint8_t accState = ACC_DISABLED;
volatile uint16_t coinPulses = 0;
uint16_t coinValue = 0;
volatile bool coinDetected = false;
volatile unsigned long lastPulseAtMs = 0;
static void IRAM_ATTR pulseIsrHandler(void* arg);
public:
const uint8_t ACC_DISABLED = LOW;
const uint8_t ACC_ENABLED = HIGH;
const unsigned int* pulseValues;
const size_t maxPulses = 0;
const uint8_t pulseWidthMs = 0;
uint8_t detectionError = 0;
CoinAcceptor(uint8_t pulsePin, uint8_t enablePin, const unsigned int* pulseValues, const size_t maxPulses, const uint8_t pulseWidthMs );
void begin();
void disable();
void enable();
uint8_t state();
bool detectCoin();
uint16_t getCoinValue();
};
#endif

View file

@ -0,0 +1,72 @@
#ifndef EPAPERDISPLAY_H
#define EPAPERDISPLAY_H
#include <GxEPD2_BW.h>
#undef USE_HSPI_FOR_EPD
#define GxEPD2_DRIVER_CLASS GxEPD2_420 // 4.2 inch Waveshare e-paper display
#define GxEPD2_DISPLAY_CLASS GxEPD2_BW<GxEPD2_DRIVER_CLASS, GxEPD2_DRIVER_CLASS::HEIGHT> // Black and White e-Paper
static const char* display_type = "GxEPD2_420";
class EpaperDisplay
{
private:
GxEPD2_DISPLAY_CLASS *epDisplay;
public:
EpaperDisplay(uint8_t DSPLY_PIN_CS, uint8_t DSPLY_PIN_DC, uint8_t DSPLY_PIN_RST, uint8_t DSPLY_PIN_BUSY);
~EpaperDisplay();
void init();
void sleep();
void homeScreen();
void showInsertedAmount(const char*);
void updateInsertedAmount(const char*);
void cleanScreen();
void drawText(const char* text, uint8_t textSize, uint16_t x, uint16_t y, uint16_t fgColor, uint16_t bgColor );
void drawText(const char* text, uint16_t x, uint16_t y);
void updateText(const char* text, uint16_t x, uint16_t y);
void updateText(const char* text, uint8_t textSize, uint16_t x, uint16_t y, uint16_t fgColor, uint16_t bgColor);
};
// Bitcoin Logo
const unsigned char bitcoin_logo[] PROGMEM = {
// 'bitcoin64, 64x64px
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0x80, 0x00, 0x00,
0x00, 0x00, 0x0f, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xfc, 0x00, 0x00,
0x00, 0x00, 0x7f, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00,
0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x0f, 0xff, 0xfc, 0x7f, 0xff, 0xf0, 0x00,
0x00, 0x1f, 0xff, 0xfc, 0x63, 0xff, 0xf8, 0x00, 0x00, 0x3f, 0xff, 0xfc, 0x63, 0xff, 0xfc, 0x00,
0x00, 0x7f, 0xfe, 0x38, 0xe3, 0xff, 0xfe, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0xe3, 0xff, 0xfe, 0x00,
0x00, 0xff, 0xfe, 0x00, 0x03, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0x00,
0x00, 0xff, 0xff, 0xc0, 0x00, 0xff, 0xff, 0x80, 0x01, 0xff, 0xff, 0xc0, 0x00, 0x7f, 0xff, 0x80,
0x01, 0xff, 0xff, 0xc1, 0xe0, 0x3f, 0xff, 0x80, 0x01, 0xff, 0xff, 0x81, 0xf8, 0x1f, 0xff, 0x80,
0x03, 0xff, 0xff, 0x83, 0xf8, 0x1f, 0xff, 0xc0, 0x03, 0xff, 0xff, 0x83, 0xf8, 0x1f, 0xff, 0xc0,
0x03, 0xff, 0xff, 0x83, 0xf8, 0x1f, 0xff, 0xc0, 0x03, 0xff, 0xff, 0x01, 0xf0, 0x1f, 0xff, 0xc0,
0x03, 0xff, 0xff, 0x00, 0x00, 0x3f, 0xff, 0xc0, 0x03, 0xff, 0xff, 0x00, 0x00, 0x7f, 0xff, 0xc0,
0x03, 0xff, 0xff, 0x06, 0x00, 0xff, 0xff, 0xc0, 0x03, 0xff, 0xfe, 0x07, 0xc0, 0x7f, 0xff, 0xc0,
0x03, 0xff, 0xfe, 0x0f, 0xe0, 0x3f, 0xff, 0xc0, 0x03, 0xff, 0xfe, 0x0f, 0xf0, 0x3f, 0xff, 0xc0,
0x03, 0xff, 0xec, 0x0f, 0xf0, 0x3f, 0xff, 0xc0, 0x03, 0xff, 0xe0, 0x0f, 0xf0, 0x3f, 0xff, 0xc0,
0x01, 0xff, 0xc0, 0x0f, 0xf0, 0x3f, 0xff, 0x80, 0x01, 0xff, 0xc0, 0x00, 0x00, 0x3f, 0xff, 0x80,
0x01, 0xff, 0xf8, 0x00, 0x00, 0x7f, 0xff, 0x80, 0x01, 0xff, 0xfe, 0x00, 0x00, 0x7f, 0xff, 0x00,
0x00, 0xff, 0xfe, 0x30, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xfe, 0x38, 0xc7, 0xff, 0xff, 0x00,
0x00, 0x7f, 0xfe, 0x31, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x7f, 0xfc, 0x31, 0xff, 0xff, 0xfe, 0x00,
0x00, 0x3f, 0xff, 0xf1, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x1f, 0xff, 0xf1, 0xff, 0xff, 0xf8, 0x00,
0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00,
0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xfe, 0x00, 0x00,
0x00, 0x00, 0x3f, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xf0, 0x00, 0x00,
0x00, 0x00, 0x01, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
#endif

View file

@ -1,146 +0,0 @@
#ifndef LIGHTNING_ATM_H
#define LIGHTNING_ATM_H
#include <Arduino.h>
#include <GxEPD2_BW.h>
#include <Fonts/FreeMonoBold9pt7b.h>
#include "qrcode.h"
#include "Bitcoin.h"
#include <stdlib.h>
#include <Hash.h>
#include <ctype.h>
#include <stdio.h>
// ########################################
// ########### USER ACTION ###########
// ########################################
// Generate and copy in LNbits with the LNURLDevice extension the string for the ATM and paste it here:
const char* lnurlDeviceString = "https://legend.lnbits.com/lnurldevice/api/v1/lnurl/idexample,keyexample,EUR";
// #################### EXAMPLE: https://legend.lnbits.com/lnurldevice/api/v1/lnurl/idexample,keyexample,EUR
// ########################################
// ########################################
// ########################################
// Activate for debugging over Serial (1), deactivate in production use (0)
#define DEBUG_MODE 1
#define COIN_PIN 17
#define PULSE_TIMEOUT 200
#define LED_BUTTON_PIN 21 // old: 13 | new: 21
#define BUTTON_PIN 32
#define MOSFET_PIN 16 // old: 12 | new: 16
#define QR_VERSION 6 // 20 is standard. 6 for simpler QR code, but does not always work.
#define DSPLY_PIN_CS 26
#define DSPLY_PIN_DC 25
#define DSPLY_PIN_RST 33
#define DSPLY_PIN_BUSY 27
#define DSPLY_PIN_CLK 18 // SCK pin SPI
#define DSPLY_PIN_DIN 23 // MOSI pin SPI
// Folowing #defines are Taken from :
//#include "GxEPD2_display_selection_new_style.h"
const uint8_t nr_supported_display_types = 6;
const char* supported_display_types[nr_supported_display_types] = {"GxEPD2_420", "GxEPD2_150_BN", "GxEPD2_270", "GxEPD2_270_GDEY027T91", "GxEPD2_213_B74", "GxEPD2_213_flex"};
#undef USE_HSPI_FOR_EPD
#define GxEPD2_DISPLAY_CLASS GxEPD2_BW // Black and White e-Paper
#define GxEPD2_DRIVER_CLASS GxEPD2_420 // 4.2 inch Waveshare e-paper display
//#define GxEPD2_DRIVER_CLASS GxEPD2_150_BN // 1.54 inch Waveshare e-paper display
const char* display_type = "GxEPD2_420";
// Treiber für das 4.2" Schwarz-Weiß E-Paper
GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, GxEPD2_DRIVER_CLASS::HEIGHT> display(GxEPD2_DRIVER_CLASS(DSPLY_PIN_CS, DSPLY_PIN_DC, DSPLY_PIN_RST, DSPLY_PIN_BUSY)); // Waveshare ESP32 Driver Board
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;
extern String baseURLATM;
extern String secretATM;
extern String currencyATM;
// Bitcoin Logo
const unsigned char bitcoin_logo[] PROGMEM = {
// 'bitcoin64, 64x64px
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0x80, 0x00, 0x00,
0x00, 0x00, 0x0f, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xfc, 0x00, 0x00,
0x00, 0x00, 0x7f, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00,
0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x0f, 0xff, 0xfc, 0x7f, 0xff, 0xf0, 0x00,
0x00, 0x1f, 0xff, 0xfc, 0x63, 0xff, 0xf8, 0x00, 0x00, 0x3f, 0xff, 0xfc, 0x63, 0xff, 0xfc, 0x00,
0x00, 0x7f, 0xfe, 0x38, 0xe3, 0xff, 0xfe, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0xe3, 0xff, 0xfe, 0x00,
0x00, 0xff, 0xfe, 0x00, 0x03, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0x00,
0x00, 0xff, 0xff, 0xc0, 0x00, 0xff, 0xff, 0x80, 0x01, 0xff, 0xff, 0xc0, 0x00, 0x7f, 0xff, 0x80,
0x01, 0xff, 0xff, 0xc1, 0xe0, 0x3f, 0xff, 0x80, 0x01, 0xff, 0xff, 0x81, 0xf8, 0x1f, 0xff, 0x80,
0x03, 0xff, 0xff, 0x83, 0xf8, 0x1f, 0xff, 0xc0, 0x03, 0xff, 0xff, 0x83, 0xf8, 0x1f, 0xff, 0xc0,
0x03, 0xff, 0xff, 0x83, 0xf8, 0x1f, 0xff, 0xc0, 0x03, 0xff, 0xff, 0x01, 0xf0, 0x1f, 0xff, 0xc0,
0x03, 0xff, 0xff, 0x00, 0x00, 0x3f, 0xff, 0xc0, 0x03, 0xff, 0xff, 0x00, 0x00, 0x7f, 0xff, 0xc0,
0x03, 0xff, 0xff, 0x06, 0x00, 0xff, 0xff, 0xc0, 0x03, 0xff, 0xfe, 0x07, 0xc0, 0x7f, 0xff, 0xc0,
0x03, 0xff, 0xfe, 0x0f, 0xe0, 0x3f, 0xff, 0xc0, 0x03, 0xff, 0xfe, 0x0f, 0xf0, 0x3f, 0xff, 0xc0,
0x03, 0xff, 0xec, 0x0f, 0xf0, 0x3f, 0xff, 0xc0, 0x03, 0xff, 0xe0, 0x0f, 0xf0, 0x3f, 0xff, 0xc0,
0x01, 0xff, 0xc0, 0x0f, 0xf0, 0x3f, 0xff, 0x80, 0x01, 0xff, 0xc0, 0x00, 0x00, 0x3f, 0xff, 0x80,
0x01, 0xff, 0xf8, 0x00, 0x00, 0x7f, 0xff, 0x80, 0x01, 0xff, 0xfe, 0x00, 0x00, 0x7f, 0xff, 0x00,
0x00, 0xff, 0xfe, 0x30, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xfe, 0x38, 0xc7, 0xff, 0xff, 0x00,
0x00, 0x7f, 0xfe, 0x31, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x7f, 0xfc, 0x31, 0xff, 0xff, 0xfe, 0x00,
0x00, 0x3f, 0xff, 0xf1, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x1f, 0xff, 0xf1, 0xff, 0xff, 0xf8, 0x00,
0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00,
0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xfe, 0x00, 0x00,
0x00, 0x00, 0x3f, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xf0, 0x00, 0x00,
0x00, 0x00, 0x01, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
// put function declarations here:
void clean_screen();
void initialize_display();
void to_upper(char* arr);
void qr_withdrawl_screen(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();
String getValue(String data, char separator, int index);
void display_sleep();
void test_macro();
// Waveshare 1.54 inch e-ink display functions
void home_screen_waveshare_1_54();
void show_inserted_amount_waveshare_1_54(String amount_in_euro);
void qr_withdrawl_screen_waveshare_1_54(const char* qr_content);
void clean_screen_waveshare_1_54();
// Waveshare 2.7 inch e-ink display functions
void home_screen_waveshare_2_7();
void show_inserted_amount_waveshare_2_7(String amount_in_euro);
void qr_withdrawl_screen_waveshare_2_7(const char* qr_content);
void clean_screen_waveshare_2_7();
// Waveshare 2.13 inch e-ink display (250x122) functions
void home_screen_waveshare_2_13();
void show_inserted_amount_waveshare_2_13(String amount_in_euro);
void qr_withdrawl_screen_waveshare_2_13(const char* qr_content);
void clean_screen_waveshare_2_13();
// Waveshare 2.13 inch e-ink display (D) flex (yellow) (212x104) functions
void home_screen_waveshare_2_13_flex();
void show_inserted_amount_waveshare_2_13_flex(String amount_in_euro);
void qr_withdrawl_screen_waveshare_2_13_flex(const char* qr_content);
void clean_screen_waveshare_2_13_flex();
#endif

100
firmware/include/main.h Normal file
View file

@ -0,0 +1,100 @@
#ifndef MAIN_H
#define MAIN_H
#include <Arduino.h>
#include <GxEPD2_BW.h>
#include <Fonts/FreeMonoBold9pt7b.h>
#include "qrcode.h"
#include "Bitcoin.h"
#include <stdlib.h>
#include <Hash.h>
#include <ctype.h>
#include <stdio.h>
// ########################################
// ########### USER ACTION ###########
// ########################################
// Generate and copy in LNbits with the LNURLDevice extension the string for the ATM and paste it here:
const char* lnurlDeviceString = "https://legend.lnbits.com/lnurldevice/api/v1/lnurl/idexample,keyexample,EUR";
// #################### EXAMPLE: https://legend.lnbits.com/lnurldevice/api/v1/lnurl/idexample,keyexample,EUR
// ########################################
// ########################################
// ########################################
// Activate for debugging over Serial (1), deactivate in production use (0)
#define DEBUG_MODE 1
#define COIN_PIN 17
#define PULSE_TIMEOUT 200
const uint8_t LED_BUTTON_PIN = 21; // old: 13 | new: 21
const uint8_t BUTTON_PIN = 32;
#define MOSFET_PIN 16 // old: 12 | new: 16
#define QR_VERSION 6 // 20 is standard. 6 for simpler QR code, but does not always work.
const uint8_t DSPLY_PIN_CS = 26;
const uint8_t DSPLY_PIN_DC = 25;
const uint8_t DSPLY_PIN_RST = 33;
const uint8_t DSPLY_PIN_BUSY = 27;
constexpr unsigned int COINS[] = { 1, 2, 5, 10, 20, 50, 100, 200};
constexpr size_t COINS_COUNT = sizeof(COINS) / sizeof(COINS[0]);
const unsigned long COIN_PULSE_WIDTH_MS = 45;
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;
extern String baseURLATM;
extern String secretATM;
extern String currencyATM;
// put function declarations here:
void clean_screen();
void initialize_display();
void to_upper(char* arr);
void qr_withdrawl_screen(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();
String getValue(String data, char separator, int index);
void display_sleep();
void test_macro();
// Waveshare 1.54 inch e-ink display functions
void home_screen_waveshare_1_54();
void show_inserted_amount_waveshare_1_54(String amount_in_euro);
void qr_withdrawl_screen_waveshare_1_54(const char* qr_content);
void clean_screen_waveshare_1_54();
// Waveshare 2.7 inch e-ink display functions
void home_screen_waveshare_2_7();
void show_inserted_amount_waveshare_2_7(String amount_in_euro);
void qr_withdrawl_screen_waveshare_2_7(const char* qr_content);
void clean_screen_waveshare_2_7();
// Waveshare 2.13 inch e-ink display (250x122) functions
void home_screen_waveshare_2_13();
void show_inserted_amount_waveshare_2_13(String amount_in_euro);
void qr_withdrawl_screen_waveshare_2_13(const char* qr_content);
void clean_screen_waveshare_2_13();
// Waveshare 2.13 inch e-ink display (D) flex (yellow) (212x104) functions
void home_screen_waveshare_2_13_flex();
void show_inserted_amount_waveshare_2_13_flex(String amount_in_euro);
void qr_withdrawl_screen_waveshare_2_13_flex(const char* qr_content);
void clean_screen_waveshare_2_13_flex();
#endif

81
firmware/src/button.cpp Normal file
View file

@ -0,0 +1,81 @@
#include "button.h"
// Konstruktor
AtmButton::AtmButton(uint8_t buttonPin, uint8_t buttonLedPin) : pin(buttonPin), ledPin(buttonLedPin), pressed(false) {}
// Initialisierung des Pins & Interrupts
void AtmButton::begin() {
pinMode(ledPin, OUTPUT);
pinMode(pin, INPUT_PULLUP);
ledOff();
attachInterruptArg(digitalPinToInterrupt(pin), buttonIsrHandler, this, FALLING);
}
void IRAM_ATTR AtmButton::buttonIsrHandler(void* arg) {
AtmButton* self = static_cast<AtmButton*>(arg);
unsigned long current_ms = millis();
if((false == self->pressed) && ((current_ms - self->last_pressed_ms) > self->DEBOUNCE_BUTTON_MS))
{
self->pressed = true;
self->pressed_at_ms = current_ms;
self->pressed_after_ms = current_ms - self->last_pressed_ms;
self->last_pressed_ms = current_ms;
}
self->pressed = true;
}
bool AtmButton::wasPressed() {
if (pressed) {
pressed = false; // Reset des Status
return true;
}
return false;
}
void AtmButton::ledOn() {
digitalWrite(ledPin, LEDON);
ledState = LEDON;
}
void AtmButton::ledOff() {
digitalWrite(ledPin, LEDOFF);
ledState = LEDOFF;
}
void AtmButton::ledToggle() {
ledState = (LEDON == ledState) ? LEDOFF : LEDON;
digitalWrite(ledPin, ledState);
}
bool AtmButton::iswaitingUntilPressed(unsigned long maxTimeToWaitMs, unsigned long blinkPeriodMs)
{
/* will return as longs as waiting until the button is pressed */
/* if blinkPeriodMs is 0 - there is no LED blinking */
unsigned long currentMs = millis();
if(false == activeWaiting)
{
activeWaiting = true;
pressed = false;
startWaitTime = currentMs;
lastWaitLedToggle = currentMs;
ledOn();
}
if( (true == pressed) || ((currentMs - startWaitTime) >= maxTimeToWaitMs))
{
ledOff();
activeWaiting = false;
return false;
}
if( (currentMs - lastWaitLedToggle) >= blinkPeriodMs )
{
lastWaitLedToggle = currentMs;
ledToggle();
}
return true;
}

View file

@ -0,0 +1,84 @@
#include "coinacceptor.h"
CoinAcceptor::CoinAcceptor(uint8_t pulsePin, uint8_t enablePin, const unsigned int* pulseValues, const size_t maxPulses, const uint8_t pulseWidthMs) :
pulsePin(pulsePin), enablePin(enablePin), pulseValues(pulseValues), maxPulses(maxPulses), pulseWidthMs(pulseWidthMs) {}
// Initialisierung des Pins & Interrupts
void CoinAcceptor::begin() {
pinMode(enablePin, OUTPUT);
pinMode(pulsePin, INPUT_PULLUP);
disable();
if(digitalRead(pulsePin) == HIGH)
{
Serial.println("Attaching interrupt to falling edge of coin acceptor pulse pin.");
attachInterruptArg(digitalPinToInterrupt(pulsePin), pulseIsrHandler, this, FALLING);
}
else
{
Serial.println("Attaching interrupt to rising edge of coin acceptor pulse pin.");
attachInterruptArg(digitalPinToInterrupt(pulsePin), pulseIsrHandler, this, RISING);
}
}
void IRAM_ATTR CoinAcceptor::pulseIsrHandler(void* arg) {
CoinAcceptor* self = static_cast<CoinAcceptor*>(arg);
unsigned long currentMs = micros()/1000;
if((self->lastPulseAtMs == 0) || ((currentMs - self->lastPulseAtMs) > 1.5*self->pulseWidthMs))
{
self->coinDetected = true;
self->lastPulseAtMs = currentMs;
self->coinPulses++;
}
}
void CoinAcceptor::disable() {
accState = ACC_DISABLED;
digitalWrite(enablePin, accState);
}
void CoinAcceptor::enable() {
accState = ACC_ENABLED;
coinDetected = false;
detectionError = 0;
coinPulses = 0;
coinValue = 0;
lastPulseAtMs = 0;
digitalWrite(enablePin, accState);
}
uint8_t CoinAcceptor::state() {
return accState;
}
bool CoinAcceptor::detectCoin() {
if(true == coinDetected)
{
disable();
long lastPulseBeforeMs = 0;
long maxMsSinceLastPulse = 8*pulseWidthMs;
do
{
lastPulseBeforeMs = millis() - lastPulseAtMs;
} while ((lastPulseAtMs == 0) || (lastPulseBeforeMs < maxMsSinceLastPulse ));
Serial.printf("DONE --- Pulses: %d, Last pulse before: %d ms (max allowed: %d). \n", coinPulses, lastPulseBeforeMs, maxMsSinceLastPulse);
// there is one additial edge in the signal ... remove it
coinPulses--;
if((coinPulses > 1) && (coinPulses <= maxPulses))
{
coinValue = pulseValues[coinPulses-1]; // coin array index is running from 0 to maxPulses-1 ...
Serial.printf(" --- Detected coin value: %d cents\n", coinValue);
}
else
{
Serial.printf(" ERROR --- Number of pulses doesn't match any teached coin value\n");
detectionError++;
}
coinDetected = false;
return true;
}
return false;
}
uint16_t CoinAcceptor::getCoinValue() {
return coinValue;
}

View file

@ -0,0 +1,154 @@
#include "epaperdisplay.h"
// *** for Waveshare ESP32 Driver board *** //
#if defined(ESP32) && defined(USE_HSPI_FOR_EPD)
SPIClass hspi(HSPI);
#endif
// *** end Waveshare ESP32 Driver board *** //
EpaperDisplay::EpaperDisplay(uint8_t DSPLY_PIN_CS, uint8_t DSPLY_PIN_DC, uint8_t DSPLY_PIN_RST, uint8_t DSPLY_PIN_BUSY)
{
epDisplay = new GxEPD2_DISPLAY_CLASS(GxEPD2_DRIVER_CLASS(DSPLY_PIN_CS, DSPLY_PIN_DC, DSPLY_PIN_RST, DSPLY_PIN_BUSY));
}
EpaperDisplay::~EpaperDisplay()
{
}
void EpaperDisplay::sleep()
{
epDisplay->hibernate();
}
void EpaperDisplay::init()
{
epDisplay->init(115200, true, 2, false);
// *** for Waveshare ESP32 Driver board *** //
#if defined(ESP32) && defined(USE_HSPI_FOR_EPD)
hspi.begin(13, 12, 14, 15); // remap hspi for EPD (swap pins)
epDisplay>epd2.selectSPI(hspi, SPISettings(4000000, MSBFIRST, SPI_MODE0));
#endif
epDisplay->setRotation(1);
}
void EpaperDisplay::cleanScreen()
{
epDisplay->firstPage();
do{
epDisplay->clearScreen();
}
while(epDisplay->nextPage());
epDisplay->hibernate();
}
void EpaperDisplay::drawText(const char* text, uint16_t x, uint16_t y)
{
epDisplay->setCursor(x, y);
epDisplay->printf(text);
}
void EpaperDisplay::drawText(const char* text, uint8_t textSize, uint16_t x, uint16_t y, uint16_t fgColor, uint16_t bgColor )
{
epDisplay->setTextSize(textSize);
epDisplay->setTextColor(fgColor, bgColor);
drawText(text, x, y);
}
void EpaperDisplay::updateText(const char* text, uint16_t x, uint16_t y)
{
int16_t xul, yul;
uint16_t textWidth, textHeight;
epDisplay->getTextBounds(text, x, y, &xul, &yul, &textWidth, &textHeight);
epDisplay->setPartialWindow(xul, yul, textWidth, textHeight);
epDisplay->firstPage();
do
{
epDisplay->setCursor(x, y);
epDisplay->printf(text);
} while (epDisplay->nextPage());
}
void EpaperDisplay::updateText(const char* text, uint8_t textSize, uint16_t x, uint16_t y, uint16_t fgColor, uint16_t bgColor)
{
epDisplay->setTextSize(textSize);
epDisplay->setTextColor(fgColor, bgColor);
updateText(text, x, y);
}
void EpaperDisplay::homeScreen()
{
epDisplay->setFullWindow();
epDisplay->firstPage();
do
{
drawText("Insert Euro coins\n on the right ->\n to start ATM\n", 2, 11, 20, GxEPD_BLACK, GxEPD_WHITE);
epDisplay->drawBitmap(172, 65, bitcoin_logo, 64, 64, GxEPD_BLACK);
drawText("Prepare Lightning enabled Bitcoin\n wallet before starting!\n Supported coins: 1 - 50 Cent, 1 - 2 Euro\n", 1, 12, 140, GxEPD_BLACK, GxEPD_WHITE);
} while (epDisplay->nextPage());
epDisplay->hibernate();
}
void EpaperDisplay::showInsertedAmount(const char* amount_in_euro)
{
epDisplay->setFullWindow();
epDisplay->firstPage();
do
{
drawText("Inserted amount:\n", 2, 11, 10, GxEPD_BLACK, GxEPD_WHITE);
drawText(amount_in_euro, 3, 20, 75, GxEPD_BLACK, GxEPD_WHITE);
drawText("Press button\n once finished.\n", 2, 11, 135, GxEPD_BLACK, GxEPD_WHITE);
} while (epDisplay->nextPage());
}
void EpaperDisplay::updateInsertedAmount(const char* amount_in_euro)
{
updateText(amount_in_euro, 3, 20, 75, GxEPD_BLACK, GxEPD_WHITE);
}
#if 0
void qr_withdrawl_screen_waveshare_2_7(const char* qr_content)
{
QRCode qrcoded;
uint8_t qrcodeData[qrcode_getBufferSize(QR_VERSION)]; // 20 is "qr version"
t_qrdata qr;
qrcode_initText(&qrcoded, qrcodeData, QR_VERSION, 0, qr_content);
qr.qr_size = qrcoded.size * 3;
qr.start_x = (264 - qr.qr_size) / 2;
qr.start_y = (176 - qr.qr_size) / 2;
qr.module_size = 3;
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(11, 5);
display.setTextSize(2);
display.setTextColor(GxEPD_BLACK, GxEPD_WHITE);
display.println("Please scan QR code:"); // top message
display.setCursor(11, 155);
display.setTextSize(2);
display.setTextColor(GxEPD_BLACK, GxEPD_WHITE);
display.println("Reset - press button"); // bottom message
display.nextPage();
display.hibernate();
}
#endif

View file

@ -1,126 +1,47 @@
#if 0 #include "main.h"
#include "lightning_atm.h" #include "epaperdisplay.h"
#include "button.h"
#include "coinacceptor.h"
//#include <GxEPD2_BW.h> // Bibliothek für Schwarz-Weiß-Displays EpaperDisplay epDisp(DSPLY_PIN_CS, DSPLY_PIN_DC, DSPLY_PIN_RST, DSPLY_PIN_BUSY);
#include <Fonts/FreeMonoBold9pt7b.h> AtmButton button(BUTTON_PIN, LED_BUTTON_PIN);
CoinAcceptor cacc(COIN_PIN, MOSFET_PIN, COINS, COINS_COUNT, COIN_PULSE_WIDTH_MS);
// #define EPD_CS 26 /*------------*/
// #define EPD_DC 25
// #define EPD_RST 33
// #define EPD_BUSY 27
// // Treiber für das 4.2" Schwarz-Weiß E-Paper
// GxEPD2_BW<GxEPD2_420, GxEPD2_420::HEIGHT> display(GxEPD2_420(EPD_CS, EPD_DC, EPD_RST, EPD_BUSY));
void drawText(const char* text);
void setup() {
Serial.begin(115200);
/* Wichtige Pins manuell setzen
pinMode(EPD_CS, OUTPUT);
pinMode(EPD_DC, OUTPUT);
pinMode(EPD_RST, OUTPUT);
pinMode(EPD_BUSY, INPUT); // BUSY muss als INPUT definiert werden! */
display.init(115200, true, 2, false);
display.setRotation(1); // 0 = Hochformat, 1 = Querformat
// Bildschirm löschen
display.setFullWindow();
display.firstPage();
do {
display.fillScreen(GxEPD_WHITE);
} while (display.nextPage());
delay(1000);
drawText("Text Nummer Eins."); // Beispieltext anzeigen
delay(10000);
drawText("Text Nummer Zwei."); // Beispieltext anzeigen
}
void loop() {
}
void drawText(const char* text) {
Serial.printf("Text to show: '%s'\n",text);
display.setFullWindow();
display.firstPage();
do {
display.setCursor(50, 100);
display.setFont(&FreeMonoBold9pt7b);
display.setTextColor(GxEPD_BLACK);
display.print(text);
} while (display.nextPage());
Serial.println("Display updated.");
}
#else
#include "lightning_atm.h"
constexpr unsigned int COINS[] = { 0, 0, 5, 10, 20, 50, 100, 200, 1, 2 };
volatile bool button_pressed = false;
static unsigned int inserted_cents = 0;
static unsigned int pulses = 0;
static unsigned long long time_last_press = millis();
String baseURLATM, secretATM, currencyATM; String baseURLATM, secretATM, currencyATM;
// *** for Waveshare ESP32 Driver board *** //
#if defined(ESP32) && defined(USE_HSPI_FOR_EPD)
SPIClass hspi(HSPI);
#endif
// *** end Waveshare ESP32 Driver board *** //
//GxEPD2_BW<GxEPD2_420, GxEPD2_420::HEIGHT> display(GxEPD2_420(DSPLY_PIN_CS, DSPLY_PIN_DC, DSPLY_PIN_RST, DSPLY_PIN_BUSY));
//GxEPD2_BW<GxEPD2_154, GxEPD2_154::HEIGHT> display(GxEPD2_154(DSPLY_PIN_CS, DSPLY_PIN_DC, DSPLY_PIN_RST, DSPLY_PIN_BUSY));
void IRAM_ATTR button_pressed_itr() {
button_pressed = true;
}
void setup() void setup()
{ {
Serial.begin(115200); Serial.begin(115200);
cacc.begin();
button.begin();
epDisp.init();
epDisp.homeScreen();
initialize_display(); // connection to the e-ink display while(0 == 0)
home_screen();
Serial.printf("Selected display type: %s\n", display_type);
while(0 == 0){}
// *** for Waveshare ESP32 Driver board *** //
#if defined(ESP32) && defined(USE_HSPI_FOR_EPD)
hspi.begin(13, 12, 14, 15); // remap hspi for EPD (swap pins)
display.epd2.selectSPI(hspi, SPISettings(4000000, MSBFIRST, SPI_MODE0));
#endif
// *** end Waveshare ESP32 Driver board *** //
if (DEBUG_MODE) // serial connection for debugging over USB
{ {
sleep(3); Serial.println("Insert coin please.");
Serial.println("Setup with debug mode..."); // for monitoring with serial monitor to debug cacc.enable();
Serial.printf("Selected display type: %s\n", display_type); do
{
} while (false == cacc.detectCoin());
delay(1000);
} }
pinMode(COIN_PIN, INPUT_PULLUP); // coin acceptor input
pinMode(LED_BUTTON_PIN, OUTPUT); // LED of the LED Button
pinMode(BUTTON_PIN, INPUT_PULLUP); // Button
pinMode(MOSFET_PIN, OUTPUT); // mosfet relay to block the coin acceptor
digitalWrite(MOSFET_PIN, LOW); // set it low to accept coins, high to block coins
attachInterrupt(BUTTON_PIN, button_pressed_itr, FALLING); // interrupt, will set button_pressed to true when button is pressed
home_screen(); // will show first screen
digitalWrite(LED_BUTTON_PIN, HIGH); // light up the led
baseURLATM = getValue(lnurlDeviceString, ',', 0); // setup wallet data from string baseURLATM = getValue(lnurlDeviceString, ',', 0); // setup wallet data from string
secretATM = getValue(lnurlDeviceString, ',', 1); secretATM = getValue(lnurlDeviceString, ',', 1);
currencyATM = getValue(lnurlDeviceString, ',', 2); currencyATM = getValue(lnurlDeviceString, ',', 2);
while(0==0)
{delay(1000);}
} }
void loop() void loop()
{ {
#if 0
pulses = 0; pulses = 0;
pulses = detect_coin(); // detect_coin() is a loop to detect the input of coins, will return the amount of pulses pulses = detect_coin(); // detect_coin() is a loop to detect the input of coins, will return the amount of pulses
if (pulses >= 2 && pulses <= 9) if (pulses >= 2 && pulses <= 9)
@ -172,228 +93,11 @@ void loop()
home_screen(); home_screen();
} }
} }
} #endif
// blocking loop which is called when the qr code is shown
void wait_for_user_to_scan()
{
unsigned long long time;
bool light_on;
if (DEBUG_MODE)
Serial.println("Waiting for user to scan qr code and press button...");
light_on = true;
time = millis(); // save start time
digitalWrite(LED_BUTTON_PIN, HIGH); // light up the led
delay(5000);
button_pressed = false;
Serial.println("wait for user to press button or 10 minutes to go back to home screen");
while (!button_pressed && (millis() - time) < 600000)
{
if (!light_on && (millis() - time) > 30000)
{
digitalWrite(LED_BUTTON_PIN, HIGH);
light_on = true;
}
else if (light_on && (millis() - time) > 30000)
{
digitalWrite(LED_BUTTON_PIN, LOW);
light_on = false;
}
delay(500);
}
Serial.println("Exit waiting");
}
unsigned int detect_coin()
{
unsigned long last_pulse;
unsigned int pulses;
bool prev_value;
bool read_value;
unsigned long entering_time;
unsigned long current_time;
if (DEBUG_MODE)
Serial.println("Starting coin detection...");
pulses = 0;
read_value = 1;
prev_value = digitalRead(COIN_PIN);
digitalWrite(LED_BUTTON_PIN, HIGH);
digitalWrite(MOSFET_PIN, LOW);
button_pressed = false;
entering_time = millis();
while (true && !button_pressed)
{
read_value = digitalRead(COIN_PIN);
if (read_value != prev_value && !read_value)
{
delay(35);
read_value = digitalRead(COIN_PIN);
if (!read_value)
{
pulses++;
last_pulse = millis();
digitalWrite(MOSFET_PIN, HIGH);
}
}
prev_value = read_value;
current_time = millis();
if (pulses > 0 && (current_time - last_pulse > PULSE_TIMEOUT))
{
break;
}
else if (pulses == 0 && ((current_time - entering_time) > 43200000) // refreshes the screen every 12h
&& inserted_cents == 0)
{
clean_screen();
delay(10000);
entering_time = millis();
home_screen();
}
else if (inserted_cents > 0 && (current_time - entering_time) > 360000) // break the loop if no new coin is inserted for some time
button_pressed = true;
}
if (DEBUG_MODE)
Serial.println("Pulses: " + String(pulses));
if (button_pressed)
{
if (DEBUG_MODE)
Serial.println("Button pressed, stopping coin detection");
return (0);
}
return (pulses);
}
/*
** DISPLAY UTILS
*/
bool display_check_type(const char* in_display_type)
{
for(size_t type_nr = 0; type_nr < nr_supported_display_types; type_nr++)
{
if(0 == strcmp(supported_display_types[type_nr], in_display_type))
{
return true;
}
}
Serial.printf("No suitable display class '%s' defined.\n", in_display_type);
return false;
}
// sleep is to put the screen in hibernation mode for longer static frames
void display_sleep()
{
display.hibernate();
}
void initialize_display()
{
display.init(115200, true, 2, false);
}
void home_screen()
{
if (display_type == "GxEPD2_150_BN")
home_screen_waveshare_1_54();
else if (display_type == "GxEPD2_270")
home_screen_waveshare_2_7();
else if (display_type == "GxEPD2_270_GDEY027T91")
home_screen_waveshare_2_7();
else if (display_type == "GxEPD2_213_B74")
home_screen_waveshare_2_13();
else if (display_type == "GxEPD2_213_flex")
home_screen_waveshare_2_13_flex();
else if (display_type == "GxEPD2_420")
home_screen_waveshare_2_13_flex();
else
Serial.println("No suitable display class defined.");
if (DEBUG_MODE)
Serial.println("Home screen printed.");
}
void show_inserted_amount(int amount_in_cents)
{
String amount_in_euro_string;
amount_in_euro_string = get_amount_string(amount_in_cents);
if (display_type == "GxEPD2_150_BN")
show_inserted_amount_waveshare_1_54(amount_in_euro_string);
else if (display_type == "GxEPD2_270")
show_inserted_amount_waveshare_2_7(amount_in_euro_string);
else if (display_type == "GxEPD2_270_GDEY027T91")
show_inserted_amount_waveshare_2_7(amount_in_euro_string);
else if (display_type == "GxEPD2_213_B74")
show_inserted_amount_waveshare_2_13(amount_in_euro_string);
else if (display_type == "GxEPD2_213_flex")
show_inserted_amount_waveshare_2_13_flex(amount_in_euro_string);
else
Serial.println("No suitable display class defined.");
if (DEBUG_MODE)
Serial.println("New amount on screen.");
}
void qr_withdrawl_screen(const char* qr_content)
{
if (display_type == "GxEPD2_150_BN")
qr_withdrawl_screen_waveshare_1_54(qr_content);
else if (display_type == "GxEPD2_270")
qr_withdrawl_screen_waveshare_2_7(qr_content);
else if (display_type == "GxEPD2_270_GDEY027T91")
qr_withdrawl_screen_waveshare_2_7(qr_content);
else if (display_type == "GxEPD2_213_B74")
qr_withdrawl_screen_waveshare_2_13(qr_content);
else if (display_type == "GxEPD2_213_flex")
qr_withdrawl_screen_waveshare_2_13_flex(qr_content);
else
Serial.println("No suitable display class defined.");
if (DEBUG_MODE)
Serial.println("QR generated and Withdrawl screen printed.");
} }
// Called to clean the e-ink screen for storage over longer periods
// by button presses on home screen
void clean_screen()
{
if (DEBUG_MODE)
Serial.println("Cleaning screen...");
if (display_type == "GxEPD2_150_BN")
clean_screen_waveshare_1_54();
else if (display_type == "GxEPD2_270")
clean_screen_waveshare_2_7();
else if (display_type == "GxEPD2_270_GDEY027T91")
clean_screen_waveshare_2_7();
else if (display_type == "GxEPD2_213_B74")
clean_screen_waveshare_2_13();
else if (display_type == "GxEPD2_213_flex")
clean_screen_waveshare_2_13_flex();
else
Serial.println("No suitable display class defined.");
}
// converts a cent amount to a String like "1.15 Euro"
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);
if (cent_remainder > 9)
cents = String(cent_remainder);
else if (cent_remainder < 10)
cents = "0" + String(cent_remainder);
return_value = String(euro) + "." + String(cents) + " " + currencyATM;
if (DEBUG_MODE)
Serial.println("Calculated amount string: " + return_value);
return (return_value);
}
//////////////////////////////////////////// ////////////////////////////////////////////
///////////////LNURL STUFF////////////////// ///////////////LNURL STUFF//////////////////
@ -516,422 +220,3 @@ String getValue(const String data, char separator, int index)
} }
return found > index ? data.substring(strIndex[0], strIndex[1]) : ""; return found > index ? data.substring(strIndex[0], strIndex[1]) : "";
} }
// Display functions for specific display types
// ################################################################
// # Waveshare 1.54 inch e-Paper Display Modul with SPI Interface #
// ################################################################
void home_screen_waveshare_1_54()
{
if (DEBUG_MODE)
Serial.println("Home screen for Waveshare 1.54 inch display...");
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!\n\nSupported coins:\n5 - 50 Cent and 1 - 2 Euro");
display.nextPage();
display.hibernate();
}
void show_inserted_amount_waveshare_1_54(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:");
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();
}
void qr_withdrawl_screen_waveshare_1_54(const char* qr_content)
{
QRCode qrcoded;
uint8_t qrcodeData[qrcode_getBufferSize(QR_VERSION)]; // 20 is "qr version"
t_qrdata qr;
// initialize qr code data
qrcode_initText(&qrcoded, qrcodeData, QR_VERSION, 0, qr_content);
qr.qr_size = qrcoded.size * 2;
qr.start_x = (150 - qr.qr_size) / 2;
qr.start_y = (150 - qr.qr_size) / 2;
qr.module_size = 3;
display.setRotation(1);
display.setFullWindow();
display.firstPage();
// loop trough Y and X axis to draw the qr code rectangle by rectangle
// 0, 0 is the top left of the screen
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);
}
}
// draw the text messages on the screen
display.setCursor(0, 4);
display.setTextSize(2);
display.setTextColor(GxEPD_BLACK, GxEPD_WHITE);
display.println("Please scan QR:"); // top message
display.setCursor(0, 170);
display.setTextSize(2);
display.setTextColor(GxEPD_BLACK, GxEPD_WHITE);
display.println("Press the \nbutton to reset"); // bottom message
display.nextPage();
display.hibernate();
}
void clean_screen_waveshare_1_54()
{
display.firstPage();
display.nextPage();
display.hibernate();
}
// ##############################################
// # Waveshare 2.7 inch e-ink display functions #
// ##############################################
void home_screen_waveshare_2_7()
{
display.setRotation(1);
display.setFullWindow();
display.firstPage();
display.setCursor(11, 20);
display.setTextSize(2);
display.setTextColor(GxEPD_BLACK, GxEPD_WHITE);
display.println("Insert Euro coins\n on the right ->\n to start ATM");
display.drawBitmap(172, 65, bitcoin_logo, 64, 64, GxEPD_BLACK);
display.setCursor(12, 140);
display.setTextSize(1);
display.setTextColor(GxEPD_BLACK, GxEPD_WHITE);
display.println("Prepare Lightning enabled Bitcoin\n wallet before starting!\n Supported coins: 5 - 50 Cent, 1 - 2 Euro");
display.nextPage();
display.hibernate();
}
void show_inserted_amount_waveshare_2_7(String amount_in_euro)
{
display.setRotation(1);
display.setFullWindow();
display.firstPage();
display.setCursor(11, 10);
display.setTextSize(2);
display.setTextColor(GxEPD_BLACK, GxEPD_WHITE);
display.println("Inserted amount:");
display.setCursor(20, 75);
display.setTextSize(3);
display.setTextColor(GxEPD_BLACK, GxEPD_WHITE);
display.println(amount_in_euro);
display.setCursor(11, 135);
display.setTextSize(2);
display.setTextColor(GxEPD_BLACK, GxEPD_WHITE);
display.println("Press button\n once finished.");
display.nextPage();
}
void qr_withdrawl_screen_waveshare_2_7(const char* qr_content)
{
QRCode qrcoded;
uint8_t qrcodeData[qrcode_getBufferSize(QR_VERSION)]; // 20 is "qr version"
t_qrdata qr;
qrcode_initText(&qrcoded, qrcodeData, QR_VERSION, 0, qr_content);
qr.qr_size = qrcoded.size * 3;
qr.start_x = (264 - qr.qr_size) / 2;
qr.start_y = (176 - qr.qr_size) / 2;
qr.module_size = 3;
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(11, 5);
display.setTextSize(2);
display.setTextColor(GxEPD_BLACK, GxEPD_WHITE);
display.println("Please scan QR code:"); // top message
display.setCursor(11, 155);
display.setTextSize(2);
display.setTextColor(GxEPD_BLACK, GxEPD_WHITE);
display.println("Reset - press button"); // bottom message
display.nextPage();
display.hibernate();
}
void clean_screen_waveshare_2_7()
{
display.firstPage();
display.nextPage();
display.hibernate();
}
// #########################################################
// # Waveshare 2.13 inch e-ink display (250x122) functions #
// #########################################################
void home_screen_waveshare_2_13()
{
display.setRotation(1);
display.setFullWindow();
display.firstPage();
display.setCursor(5, 5);
display.setTextSize(2);
display.setTextColor(GxEPD_BLACK, GxEPD_WHITE);
display.println("LIGHTNING ATM");
display.setCursor(3, 33);
display.println("Insert coins");
display.setCursor(3, 50);
display.println("on the right");
display.setCursor(3, 67);
display.println("side to start");
display.drawBitmap(180, 15, bitcoin_logo, 64, 64, GxEPD_BLACK);
display.setCursor(0, 95);
display.setTextSize(1);
display.setTextColor(GxEPD_BLACK, GxEPD_WHITE);
display.println(" Prepare Lightning enabled Bitcoin\n wallet before starting!\n Supported coins: 2 cent to 2 euro");
display.nextPage();
display.hibernate();
}
void show_inserted_amount_waveshare_2_13(String amount_in_euro)
{
display.setRotation(1);
display.setFullWindow();
display.firstPage();
display.setCursor(10, 4);
display.setTextSize(2);
display.setTextColor(GxEPD_BLACK, GxEPD_WHITE);
display.println("Inserted amount:");
display.setCursor(35, 45);
display.setTextSize(3);
display.setTextColor(GxEPD_BLACK, GxEPD_WHITE);
display.println(amount_in_euro);
display.setCursor(0, 85);
display.setTextSize(2);
display.setTextColor(GxEPD_BLACK, GxEPD_WHITE);
display.println(" Press button\n to show QR code");
display.nextPage();
}
void qr_withdrawl_screen_waveshare_2_13(const char* qr_content)
{
QRCode qrcoded;
uint8_t qrcodeData[qrcode_getBufferSize(QR_VERSION)]; // 20 is "qr version"
t_qrdata qr;
qrcode_initText(&qrcoded, qrcodeData, QR_VERSION, 0, qr_content);
qr.qr_size = qrcoded.size * 2;
qr.start_x = (230 - qr.qr_size) / 2;
qr.start_y = (122 - 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, 20);
display.setTextSize(2);
display.setTextColor(GxEPD_BLACK, GxEPD_WHITE);
display.println(" Scan\n\n QR\n\n code"); // top message
display.setCursor(181, 32);
display.setTextSize(2);
display.setTextColor(GxEPD_BLACK, GxEPD_WHITE);
display.println("Reset");
display.setCursor(181, 53);
display.println("press");
display.setCursor(176, 77);
display.println("button");
display.nextPage();
display.hibernate();
}
void clean_screen_waveshare_2_13()
{
display.firstPage();
display.nextPage();
display.hibernate();
}
// ###########################################################################
// # Waveshare 2.13 inch e-ink display (D) flex (yellow) (212x104) functions #
// ###########################################################################
void home_screen_waveshare_2_13_flex()
{
display.setRotation(1);
display.setFullWindow();
display.firstPage();
display.setCursor(5, 5);
display.setTextSize(2);
display.setTextColor(GxEPD_BLACK, GxEPD_WHITE);
display.println("LIGHTNING ATM");
display.setCursor(3, 25);
display.println("Insert coins");
display.setCursor(3, 42);
display.println("on the right");
display.setCursor(3, 59);
display.println("side to start");
display.drawBitmap(151, 8, bitcoin_logo, 64, 64, GxEPD_BLACK);
display.setCursor(0, 80);
display.setTextSize(1);
display.setTextColor(GxEPD_BLACK, GxEPD_WHITE);
display.println(" Prepare Lightning enabled Bitcoin\n wallet before starting!\n Supported coins: 2 cent to 2 euro");
display.nextPage();
display.hibernate();
}
void show_inserted_amount_waveshare_2_13_flex(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:");
display.setCursor(30, 35);
display.setTextSize(3);
display.setTextColor(GxEPD_BLACK, GxEPD_WHITE);
display.println(amount_in_euro);
display.setCursor(0, 70);
display.setTextSize(2);
display.setTextColor(GxEPD_BLACK, GxEPD_WHITE);
display.println(" Press button\n to show QR code");
display.nextPage();
}
void qr_withdrawl_screen_waveshare_2_13_flex(const char* qr_content)
{
QRCode qrcoded;
uint8_t qrcodeData[qrcode_getBufferSize(QR_VERSION)]; // 20 is "qr version"
t_qrdata qr;
qrcode_initText(&qrcoded, qrcodeData, QR_VERSION, 0, qr_content);
qr.qr_size = qrcoded.size * 2;
qr.start_x = (220 - qr.qr_size) / 2;
qr.start_y = (105 - 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, 12);
display.setTextSize(2);
display.setTextColor(GxEPD_BLACK, GxEPD_WHITE);
display.println(" Scan\n\n QR\n\n code"); // top message
display.setCursor(170, 37);
display.setTextSize(1);
display.setTextColor(GxEPD_BLACK, GxEPD_WHITE);
display.println("Reset");
display.setCursor(170, 47);
display.println("press");
display.setCursor(167, 57);
display.println("button");
display.nextPage();
display.hibernate();
}
void clean_screen_waveshare_2_13_flex()
{
display.firstPage();
display.nextPage();
display.hibernate();
}
#endif