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

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 "lightning_atm.h"
#include "main.h"
#include "epaperdisplay.h"
#include "button.h"
#include "coinacceptor.h"
//#include <GxEPD2_BW.h> // Bibliothek für Schwarz-Weiß-Displays
#include <Fonts/FreeMonoBold9pt7b.h>
EpaperDisplay epDisp(DSPLY_PIN_CS, DSPLY_PIN_DC, DSPLY_PIN_RST, DSPLY_PIN_BUSY);
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;
// *** 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()
{
Serial.begin(115200);
cacc.begin();
button.begin();
epDisp.init();
epDisp.homeScreen();
initialize_display(); // connection to the e-ink display
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
while(0 == 0)
{
sleep(3);
Serial.println("Setup with debug mode..."); // for monitoring with serial monitor to debug
Serial.printf("Selected display type: %s\n", display_type);
}
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
Serial.println("Insert coin please.");
cacc.enable();
do
{
} while (false == cacc.detectCoin());
delay(1000);
}
baseURLATM = getValue(lnurlDeviceString, ',', 0); // setup wallet data from string
secretATM = getValue(lnurlDeviceString, ',', 1);
currencyATM = getValue(lnurlDeviceString, ',', 2);
while(0==0)
{delay(1000);}
}
void loop()
{
#if 0
pulses = 0;
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)
@ -172,228 +93,11 @@ void loop()
home_screen();
}
}
}
// 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.");
#endif
}
// 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//////////////////
@ -516,422 +220,3 @@ String getValue(const String data, char separator, int index)
}
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