#include <DNSServer.h>
#include <AsyncTCP.h>
#include <WiFi.h>
#include <HTTPClient.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
#include <QRCodeGenerator.h>
#include <ArduinoJson.h>
#include <ArduinoYaml.h>
#include <UUID.h>
#include <ESPAsyncWebServer.h>
// #include "freertos/FreeRTOS.h"
// #include "freertos/task.h"
const char* ssid = "Wokwi-GUEST";
const char* password = "";
const char* api_url = "https://api.mercadopago.com/v1/payments";
const char* access_token = "APP_USR-4430999799727209-051409-d9df849e4b0b68b8e380d31ca1d0bd37-44642512";
const char* description = "Título do produto";
const char* payer_email = "[email protected]";
const bool freeMode = false;
const uint pulseIncrement = 2;
const int reconnectWifi = -1;
/*
* https://github.com/w35l3y/ArduinoLibraries/tree/main/DigitalOutput
*/
#ifndef __DIGITAL_OUTPUT_H__
#define __DIGITAL_OUTPUT_H__
#define DIGITAL_OUTPUT_STATIC_MODE 0
#define DIGITAL_OUTPUT_BLINK_MODE_FINITE 1
#define DIGITAL_OUTPUT_BLINK_MODE_INFINITE 2
class DigitalOutput {
private:
unsigned mode = DIGITAL_OUTPUT_STATIC_MODE;
bool lastState = false;
bool lastStateBeforeBlink = false;
bool inverted = false;
unsigned int pin;
unsigned int times = 0;
unsigned long statusOn = 0L;
unsigned long statusOff = 0L;
unsigned long lastStatus = 0L;
void localTurn(bool state);
public:
DigitalOutput(unsigned int pin, bool inverted = false);
void turn(bool state);
void turnOn();
void turnOff();
void play();
void stop();
void blink(unsigned int times = 0, unsigned long statusOn = 100L, unsigned long statusOff = 100L);
void loop();
};
#endif
DigitalOutput::DigitalOutput(unsigned int pin, bool inverted) {
pinMode(pin, OUTPUT);
this->pin = pin;
this->inverted = inverted;
bool state = digitalRead(pin);
this->lastStateBeforeBlink = this->lastState = (inverted ? !state : state);
}
void DigitalOutput::localTurn(bool state) {
this->lastStatus = millis();
this->lastState = state;
digitalWrite(this->pin, (this->inverted ? !state : state));
}
void DigitalOutput::turn(bool state) {
this->mode = DIGITAL_OUTPUT_STATIC_MODE;
this->times = 0;
this->localTurn(state);
}
void DigitalOutput::turnOn() {
this->turn(true);
}
void DigitalOutput::play() {
this->turnOn();
}
void DigitalOutput::turnOff() {
this->turn(false);
}
void DigitalOutput::stop() {
this->turnOff();
}
void DigitalOutput::loop() {
if (this->mode == DIGITAL_OUTPUT_BLINK_MODE_INFINITE) {
unsigned long diff = millis() - this->lastStatus;
if (this->lastState && diff >= this->statusOn || !this->lastState && diff >= this->statusOff) {
this->localTurn(!this->lastState);
}
} else if (this->times > 0) {
unsigned long diff = millis() - this->lastStatus;
if (!this->lastState && diff >= this->statusOff) {
this->localTurn(true);
} else if (this->lastState && diff >= this->statusOn) {
this->localTurn(false);
--this->times;
}
} else if (this->mode == DIGITAL_OUTPUT_BLINK_MODE_FINITE) {
this->turn(this->lastStateBeforeBlink);
}
}
void DigitalOutput::blink(unsigned int times, unsigned long statusOn, unsigned long statusOff) {
this->mode = (times == 0 ? DIGITAL_OUTPUT_BLINK_MODE_INFINITE : DIGITAL_OUTPUT_BLINK_MODE_FINITE);
this->lastStateBeforeBlink = this->lastState;
this->times = times;
this->statusOn = statusOn;
this->statusOff = statusOff;
this->loop(); // executa efeito imediatamente
}
/*
* Esta biblioteca é mais apropriada para controlar pushbutton de pullup.
*
* Controla efeito debounce
* Orientado a evento
* Diferencia clique curto do longo
* Atua com o número de cliques customizado (1, 2, 3+)
*/
#ifndef __PUSH_BUTTON_H__
#define __PUSH_BUTTON_H__
#define PUSHBUTTON_RELEASE_MODE 0
#define PUSHBUTTON_PRESS_MODE 1
#define PUSHBUTTON_LONG_PRESS_MS 200
class PushButton {
private:
unsigned int pin;
bool longPress = false;
unsigned int times = 0;
unsigned long debounce = 0L;
void (*callback)();
unsigned long lastPress = 0;
unsigned int lastMode = PUSHBUTTON_PRESS_MODE;
unsigned int timesPressed = 0;
public:
PushButton(unsigned int pin, bool longPress = false, unsigned long debounce = 15);
bool pressed();
void loop();
void onPress(unsigned int times, void (*f)());
void onSinglePress(void (*f)());
void onDoublePress(void (*f)());
unsigned long lastPressed();
};
#endif
PushButton::PushButton(unsigned int pin, bool longPress, unsigned long debounce) {
this->pin = pin;
this->longPress = longPress;
this->debounce = debounce;
pinMode(pin, INPUT_PULLUP);
}
unsigned long PushButton::lastPressed() {
return millis() - this->lastPress;
}
bool PushButton::pressed() {
return !digitalRead(this->pin);
}
void PushButton::loop() {
unsigned long current = millis();
unsigned long diff = current - this->lastPress;
if (diff >= this->debounce) {
bool isPressed = this->pressed();
if (isPressed && this->lastMode == PUSHBUTTON_PRESS_MODE) {
this->lastPress = current;
this->lastMode = PUSHBUTTON_RELEASE_MODE;
} else if (!isPressed && this->lastMode == PUSHBUTTON_RELEASE_MODE) {
this->lastMode = PUSHBUTTON_PRESS_MODE;
if ((this->longPress && diff >= PUSHBUTTON_LONG_PRESS_MS) || (!this->longPress && diff < PUSHBUTTON_LONG_PRESS_MS)) {
++this->timesPressed;
if (this->timesPressed == this->times) {
this->lastPress = current;
this->callback();
this->timesPressed = 0;
}
} else {
this->timesPressed = 0;
}
}
}
}
void PushButton::onPress(unsigned int times, void (*f)()) {
this->times = times;
this->callback = f;
}
void PushButton::onSinglePress(void (*f)()) {
this->onPress(1, f);
}
void PushButton::onDoublePress(void (*f)()) {
this->onPress(2, f);
}
#ifndef __TIMER_H__
#define __TIMER_H__
class Timer {
private:
void (*ticked)(unsigned long value);
void (*finished)();
bool started = false;
unsigned long counter = 0L;
unsigned long startedAt = 0L;
unsigned long lastTick = 0L;
unsigned long tickLength = 0L;
public:
Timer(unsigned long counter, unsigned long tickLength = 1000L);
void start();
void stop();
void loop();
void onTick(void (*f)(unsigned long value));
void onFinish(void (*f)());
};
Timer::Timer(unsigned long counter, unsigned long tickLength) {
this->counter = counter;
this->tickLength = tickLength;
}
void Timer::onTick(void (*f)(unsigned long value)) {
this->ticked = f;
}
void Timer::onFinish(void (*f)()) {
this->finished = f;
}
void Timer::start() {
this->startedAt = millis();
this->started = true;
}
void Timer::stop() {
this->started = false;
}
void Timer::loop() {
if (!this->started) {
return;
}
unsigned long current = millis();
if (this->counter == 0) {
if (current - this->lastTick >= this->tickLength) {
this->lastTick = current - ((current - this->lastTick) % this->tickLength);
this->ticked((current - this->startedAt) / this->tickLength);
}
} else if (current - this->startedAt >= this->counter) {
this->stop();
this->finished();
} else if (current - this->lastTick >= this->tickLength) {
this->lastTick = current - ((current - this->lastTick) % this->tickLength);
this->ticked((this->counter + this->startedAt - current) / this->tickLength);
}
}
#endif
// 0 = D0
// 1 = D1
// 2 = D2
// 21 = D3
// 22 = D4
// 23 = D5
// 16 = D6 TX
// 17 = D7 RX
// 19 = D8
// 20 = D9
// 18 = D10
// ILI9341 240x320
#define SERIAL_DEBUG
#ifdef SERIAL_DEBUG
#define BEGIN() Serial.begin(9600)
#define PRINT(A) Serial.print(A)
#define PRINTLN(A) Serial.println(A)
#else
#define BEGIN()
#define PRINT(A)
#define PRINTLN(A)
#endif
#define PIN_BTN_OK D0
#define PIN_BTN_CANCEL D1
#define PIN_SIG_BUZZER D2
#define PIN_SIG_PULSE TX
#define PIN_TFT_CS D3
#define PIN_TFT_DC D7
#define PIN_TFT_MOSI D10
#define PIN_TFT_SCK D8
#define PIN_TFT_RST -1
#define PIN_TFT_MISO D9
Adafruit_ILI9341 tft = Adafruit_ILI9341(PIN_TFT_CS, PIN_TFT_DC, PIN_TFT_MOSI, PIN_TFT_SCK, PIN_TFT_RST, PIN_TFT_MISO);
static DNSServer dnsServer;
static AsyncWebServer server(80);
#define SIZE 4
#define WIDTH ILI9341_TFTWIDTH
#define HEIGHT ILI9341_TFTHEIGHT - 10
#define QR_VERSION (WIDTH / SIZE - 17) / 4
#define QR_ECC ECC_LOW
#define QR_SIZE (QR_VERSION * 4 + 17) * SIZE
#define LEFT_BORDER (WIDTH - QR_SIZE) / 2
#define TOP_BORDER (HEIGHT - QR_SIZE) / 2
#define START_MODE 0
#define CONFIG_MODE 1
#define OK_MODE 2
#define QRCODE_MODE 3
#define CANCEL_MODE 4
#define CONFIRM_MODE 5
#define FAIL_MODE 6
#define FREE_MODE 7
DigitalOutput buzzer(PIN_SIG_BUZZER);
DigitalOutput pulse (PIN_SIG_PULSE);
PushButton btnOk(PIN_BTN_OK);
PushButton btnOkLongPress(PIN_BTN_OK, true);
PushButton btnCancel(PIN_BTN_CANCEL);
Timer timerOk(3000);
Timer timerQrCode(90000);
Timer timerQrCodeCheck(0, 10000);
Timer timerConfirm(3000, 3000);
Timer timerCancel(3000, 3000);
Timer timerWifiSta(0, 1000);
unsigned int pulses = 0;
unsigned int mode = START_MODE;
bool online = false;
bool lastCheck = false;
String unique = "";// 111194832237 / 111633197840
bool renderQrCodeWhileChecking = false;
UUID uuid;
uint connectWifiCounter = 0;
void setText(const char *text, int16_t x = 0, int16_t y = 0, bool renderBackground = true, bool fillTextArea = true, bool centered = true, uint8_t textSize = 2, uint16_t h = 0, uint16_t textColor = ILI9341_WHITE, uint16_t bgColor = ILI9341_BLACK) {
h += 8 * textSize;
tft.setTextSize(textSize);
tft.setTextColor(textColor);
unsigned int cX = x;
unsigned int cY = y + (h - 8 * textSize) / 2;
unsigned int cW = strlen(text) * 6 * textSize;
if (centered) {
cX = x + (WIDTH - cW - x) / 2;
}
if (renderBackground) {
if (fillTextArea) {
tft.fillRect(cX, cY, cW, h, bgColor);
} else {
tft.fillRect(x, y, WIDTH - x, h, bgColor);
}
}
tft.setCursor(cX, cY);
tft.print(text);
}
void setTitle(const char *text, uint16_t bgColor = ILI9341_BLACK, uint8_t textSize = 2, uint16_t textColor = ILI9341_WHITE) {
setText(text, 0, 0, true, false, true, textSize, 4, textColor, bgColor);
}
void printQrCode (const char *text) {
PRINTLN(text);
// Generate QR code data
QRCode qrcode;
uint8_t qrcodeData[qrcode_getBufferSize(QR_VERSION)];
qrcode_initText(&qrcode, qrcodeData, QR_VERSION, QR_ECC, text);
// Display QR code on TFT display
//tft.fillRect(LEFT_BORDER, TOP_BORDER, QR_SIZE, QR_SIZE, ILI9341_BLACK); // Adjust size based on your display
for (uint8_t y = 0; y < qrcode.size; y++) {
for (uint8_t x = 0; x < qrcode.size; x++) {
if (qrcode_getModule(&qrcode, x, y)) {
tft.fillRect(LEFT_BORDER + x * SIZE, TOP_BORDER + y * SIZE, SIZE, SIZE, ILI9341_WHITE); // Adjust size based on your display
}
}
}
}
void printQrCodeWithTimer (const char *text) {
printQrCode(text);
timerQrCode.start();
timerQrCodeCheck.start();
}
void clearArea () {
// tft.fillRect(LEFT_BORDER, TOP_BORDER, WIDTH - 2 * LEFT_BORDER, HEIGHT - TOP_BORDER, ILI9341_BLACK);
PRINTLN("CLEANING AREA");
tft.fillRect(LEFT_BORDER, TOP_BORDER, WIDTH - 2 * LEFT_BORDER, HEIGHT - TOP_BORDER, ILI9341_DARKGREY); // Só para conseguir enxergar que algo está sendo feito
PRINTLN("READY");
}
void titleConnection () {
if (online) {
setTitle("- CONECTADO -", ILI9341_DARKGREEN);
} else {
setTitle("- DESCONECTADO -", ILI9341_MAROON);
}
}
void beginStartMode () {
PRINTLN("START MODE");
mode = START_MODE;
titleConnection();
// FIXME Substituir por imagem
clearArea();
printQrCode("https://tinyurl.com/wwwwesley");
setText("Wesley Menezes", 0, TOP_BORDER + 250, false);
timerWifiSta.start();
}
void beginWifiStaMode () {
if (setupWifiSta(true)) {
titleConnection();
}
}
void titleFreeMode () {
setTitle("- GRATUITO -", ILI9341_DARKCYAN);
}
void beginFreeMode () {
PRINTLN("FREE MODE");
mode = FREE_MODE;
titleFreeMode();
// FIXME Substituir por imagem
clearArea();
}
void beginStartOrFreeMode() {
if (freeMode) {
beginFreeMode();
return;
}
beginStartMode();
}
void beginConfigMode () {
// if (!btnCancel.pressed()) {
// return;
// }
PRINTLN("CONFIG MODE");
mode = CONFIG_MODE;
buzzer.blink(4);
setTitle("- CONFIGURACAO -", ILI9341_DARKCYAN);
WiFi.softAP("esp-captive");
server.begin();
IPAddress IP = WiFi.softAPIP();
dnsServer.start(53, "*", IP);
// @FIXME Trocar por dados do AP
clearArea();
setText(IP.toString().c_str(), 0, TOP_BORDER + 20);
}
void endConfigMode (bool save) {
server.end();
if (save) {
}
beginStartMode();
}
void beginOkMode () {
if (freeMode) {
titleFreeMode();
}
PRINTLN("OK MODE");
mode = OK_MODE;
pulses = 0;
clearArea();
setText("VALOR R$", 0, TOP_BORDER + 20, false, true, true, 4);
setText("ESCOLHA O VALOR", 0, TOP_BORDER + 145, false);
setText("E AGUARDE...", 0, TOP_BORDER + 170, false);
incrementOkMode();
}
void incrementOkMode () {
timerOk.stop();
buzzer.blink(1);
pulses += pulseIncrement;
char cstr[7];
sprintf_P(cstr, PSTR("%d,00"), pulses);
setText(cstr, 0, TOP_BORDER + 80, true, false, true, 5, 0, ILI9341_OLIVE);
timerOk.start();
}
void beginConfirmMode () {
mode = CONFIRM_MODE;
unique = "";
pulse.blink(pulses);
setTitle("- SUCESSO -", ILI9341_DARKGREEN);
// FIXME Substituir por imagem
clearArea();
timerConfirm.start();
}
void beginFailMode () {
mode = FAIL_MODE;
setTitle("- FALHA -", ILI9341_MAROON);
// FIXME Substituir por imagem
clearArea();
}
bool parseJsonQrCodeGeneratorResponse (int httpStatusCode, const String& jsonResponse, bool first) {
PRINTLN(jsonResponse);
DynamicJsonDocument doc(2048);
JsonDocument filter;
filter["id"] = true;
filter["status"] = true;
filter["status_detail"] = true;
filter["point_of_interaction"]["transaction_data"]["qr_code"] = true;
DeserializationError error = deserializeJson(doc, jsonResponse, DeserializationOption::Filter(filter));
if (!error && 200 <= httpStatusCode && httpStatusCode < 300) {
JsonObject obj = doc.as<JsonObject>();
String status = obj["status"];
if (status == "pending") {
unique = obj["id"].as<String>();
PRINTLN(unique);
printQrCodeWithTimer(obj["point_of_interaction"]["transaction_data"]["qr_code"]);
} else if (first && (status == "approved" || status == "rejected")) {
String detail = obj["status_detail"];
PRINTLN(detail);
return true;
} else {
beginFailMode();
char cstr[9];
sprintf(cstr, "Code %d", httpStatusCode);
setText(cstr, LEFT_BORDER, TOP_BORDER);
setText(("Status " + status).c_str(), LEFT_BORDER, TOP_BORDER + 25);
String detail = obj["status_detail"];
setText(detail.c_str(), LEFT_BORDER, TOP_BORDER + 75);
}
} else {
beginFailMode();
char cstr[9];
sprintf(cstr, "Code %d", httpStatusCode);
setText(cstr, LEFT_BORDER, TOP_BORDER);
setText("Falha ao gerar QR CODE", LEFT_BORDER, TOP_BORDER + 25);
setText(error.c_str(), LEFT_BORDER, TOP_BORDER + 75);
}
return false;
}
// https://www.mercadopago.com.br/developers/en/reference/payments/_payments/post
bool setupWifiSta (bool async) {
online = WiFi.status() == WL_CONNECTED;
if (async && connectWifiCounter > 0) {
if (online) {
connectWifiCounter = 0;
}
return online;
}
if (online) {
return false;
}
if (ssid == "") {
return false;
}
if (reconnectWifi == 0 || connectWifiCounter > reconnectWifi) {
return false;
}
++connectWifiCounter;
WiFi.begin(ssid, password, 6);
setTitle("- AGUARDE -", ILI9341_DARKCYAN);
if (!async) {
uint ai = 0;
while (WiFi.status() != WL_CONNECTED && ++ai < 50) {
delay(100);
}
online = WiFi.status() == WL_CONNECTED;
if (online) {
connectWifiCounter = 0;
}
}
return online;
}
void titleQrCodeMode () {
char cstr[18];
sprintf_P(cstr, PSTR("QR CODE R$ %d,00"), pulses);
setTitle(cstr, ILI9341_DARKCYAN);
}
void generateQrCode(bool first) {
//unique = "";
if (unique != "" && unique != NULL) {
renderQrCodeWhileChecking = true;
return;
}
HTTPClient http;
http.begin(api_url); // URL da API do Mercado Pago
http.addHeader("Authorization", String("Bearer ") + access_token); // Adiciona o token de autorização
http.addHeader("Content-Type", "application/json"); // Define o tipo de conteúdo como JSON
uuid.generate();
PRINTLN(uuid);
http.addHeader("X-Idempotency-Key", uuid.toCharArray()); // Define o tipo de conteúdo como JSON
char jsonBody[310];
sprintf_P(jsonBody, PSTR("{\"transaction_amount\":%d,\"description\":\"%s\",\"payment_method_id\":\"pix\",\"payer\":{\"email\":\"%s\"}}"), pulses, description, payer_email);
int httpStatusCode = http.POST(String(jsonBody)); // Envia a requisição POST
if (httpStatusCode > 0) {
// Recebe a resposta do servidor
const String response = http.getString();
http.end();
if (parseJsonQrCodeGeneratorResponse(httpStatusCode, response, first)) {
generateQrCode(false);
}
PRINTLN(unique);
} else {
http.end();
timerQrCode.stop();
timerQrCodeCheck.stop();
if (setupWifiSta(false)) {
titleQrCodeMode();
generateQrCode(first);
return;
}
beginFailMode();
char cstr[9];
sprintf(cstr, "Code %d", httpStatusCode);
setText(cstr, LEFT_BORDER, TOP_BORDER);
setText("Falha ao gerar QR CODE", LEFT_BORDER, TOP_BORDER + 25);
}
}
void beginQrCodeMode () {
if (freeMode) {
beginConfirmMode();
return;
}
mode = QRCODE_MODE;
lastCheck = false;
buzzer.blink(3);
titleQrCodeMode();
clearArea();
generateQrCode(true);
setText("TEMPO RESTANTE: ", LEFT_BORDER + 5, TOP_BORDER + 250, false, true, false);
timerQrCodeCheck.start();
}
void beginCancelMode () {
PRINTLN("CANCEL MODE");
mode = CANCEL_MODE;
buzzer.blink(2);
clearArea();
setTitle("- CANCELADO -", ILI9341_RED);
timerCancel.start();
}
// https://github.com/hnqca/QRCode-PIX-MercadoPago-php/blob/main/public/payment/notification.php
void parseJsonQrCodeCheckResponse (int httpStatusCode, const String& jsonResponse) {
DynamicJsonDocument doc(2048);
JsonDocument filter;
filter["status"] = true;
filter["status_detail"] = true;
filter["point_of_interaction"]["transaction_data"]["qr_code"] = true;
DeserializationError error = deserializeJson(doc, jsonResponse, DeserializationOption::Filter(filter));
if (!error && 200 <= httpStatusCode && httpStatusCode < 300) {
JsonObject obj = doc.as<JsonObject>();
String status = obj["status"];
if (status == "approved") {
beginConfirmMode();
} else if (status == "pending") {
if (lastCheck) {
beginCancelMode();
} else if (renderQrCodeWhileChecking) {
PRINTLN("LAZY LOAD QR CODE");
renderQrCodeWhileChecking = false;
printQrCodeWithTimer(obj["point_of_interaction"]["transaction_data"]["qr_code"]);
}
} else {
beginFailMode();
char cstr[9];
sprintf(cstr, "Code %d", httpStatusCode);
setText(cstr, LEFT_BORDER, TOP_BORDER);
setText(("Status " + status).c_str(), LEFT_BORDER, TOP_BORDER + 25);
String detail = obj["status_detail"];
setText(detail.c_str(), LEFT_BORDER, TOP_BORDER + 75);
}
} else {
beginFailMode();
char cstr[9];
sprintf(cstr, "Code %d", httpStatusCode);
setText(cstr, LEFT_BORDER, TOP_BORDER);
setText("Falha ao tentar obter situação do pagamento", LEFT_BORDER, TOP_BORDER + 25);
setText(error.c_str(), LEFT_BORDER, TOP_BORDER + 75);
}
}
void tickTimerQrCodeCheck (unsigned long counter) {
if (unique == "" || unique == NULL) {
return;
}
PRINTLN("CHECK QRCODE");
PRINTLN(unique);
PRINTLN(String(api_url) + "/" + unique);
HTTPClient http;
http.begin(String(api_url) + "/" + unique); // URL da API do Mercado Pago
http.addHeader("Content-Type", "application/json"); // Define o tipo de conteúdo como JSON
http.addHeader("Authorization", String("Bearer ") + access_token); // Adiciona o token de autorização
int httpStatusCode = http.GET(); // Envia a requisição GET
if (httpStatusCode > 0) {
const String response = http.getString();
http.end();
parseJsonQrCodeCheckResponse(httpStatusCode, response); // Recebe a resposta do servidor
} else {
http.end();
timerQrCode.stop();
if (setupWifiSta(false)) {
titleQrCodeMode();
tickTimerQrCodeCheck(0);
timerQrCode.start();
return;
}
beginFailMode();
char cstr[9];
sprintf(cstr, "Code %d", httpStatusCode);
setText(cstr, LEFT_BORDER, TOP_BORDER);
setText("Falha ao tentar obter situação do pagamento", LEFT_BORDER, TOP_BORDER + 25);
}
}
void beginLastQrCodeCheck () {
lastCheck = true;
tickTimerQrCodeCheck(0);
}
void tickTimerOk (unsigned long counter) {
char cstr[5];
sprintf_P(cstr, PSTR("(%02d)"), counter);
setText(cstr, 0, TOP_BORDER + 195);
}
void tickTimerQrCode (unsigned long counter) {
char cstr[3];
sprintf_P(cstr, PSTR("%02d"), counter);
setText(cstr, LEFT_BORDER + 5 + 16*6*2, TOP_BORDER + 250, true, true, false);
}
void onTimerOkFinished () {
PRINTLN("FINISHED OK");
switch (mode) {
case OK_MODE:
beginQrCodeMode();
break;
default:
timerOk.stop();
break;
}
}
void onTimerQrCodeFinished () {
PRINTLN("FINISHED QRCODE");
switch (mode) {
case QRCODE_MODE:
beginLastQrCodeCheck();
break;
default:
timerQrCode.stop();
break;
}
}
void onTimerCancelFinished () {
PRINTLN("FINISHED CANCEL");
switch (mode) {
case CANCEL_MODE:
beginStartOrFreeMode();
break;
default:
timerCancel.stop();
break;
}
}
void onTimerConfirmFinished () {
PRINTLN("FINISHED CONFIRM");
switch (mode) {
case CONFIRM_MODE:
beginStartOrFreeMode();
break;
default:
timerConfirm.stop();
break;
}
}
void onTimerOkTicked (unsigned long counter) {
switch (mode) {
case OK_MODE:
tickTimerOk(counter);
break;
default:
timerOk.stop();
break;
}
}
void onTimerQrCodeTicked (unsigned long counter) {
switch (mode) {
case QRCODE_MODE:
tickTimerQrCode(counter);
break;
default:
timerQrCode.stop();
break;
}
}
void onTimerQrCodeCheckTicked (unsigned long counter) {
switch (mode) {
case QRCODE_MODE:
tickTimerQrCodeCheck(counter);
break;
default:
timerQrCodeCheck.stop();
break;
}
}
void onTimerWifiStaTicked (unsigned long counter) {
switch (mode) {
case START_MODE:
case FREE_MODE:
beginWifiStaMode();
break;
default:
timerWifiSta.stop();
break;
}
}
void onTimerCancelTicked (unsigned long counter) {
PRINTLN("TICKED CANCEL");
onTimerCancelFinished();
}
void onTimerConfirmTicked (unsigned long counter) {
PRINTLN("TICKED CONFIRM");
onTimerConfirmFinished();
}
void onButtonOkPressed () {
PRINTLN("PRESSED OK");
switch (mode) {
case CONFIG_MODE:
endConfigMode(true);
break;
case START_MODE:
case FREE_MODE:
case CANCEL_MODE:
case CONFIRM_MODE:
case FAIL_MODE:
beginOkMode();
break;
case OK_MODE:
incrementOkMode();
break;
case QRCODE_MODE:
tickTimerQrCodeCheck(0);
break;
}
}
void onButtonOkLongPressed () {
PRINTLN("LONG PRESSED OK");
switch (mode) {
case START_MODE:
case FREE_MODE:
beginConfigMode();
break;
}
}
void onButtonCancelPressed () {
PRINTLN("PRESSED CANCEL");
switch (mode) {
case CONFIG_MODE:
endConfigMode(false);
break;
case CONFIRM_MODE:
case FAIL_MODE:
beginStartOrFreeMode();
break;
case OK_MODE:
case QRCODE_MODE:
beginCancelMode();
break;
}
}
// https://github.com/PaulStoffregen/ILI9341_t3/blob/f9f10ea8c1ce3e93f672c9b1e17fa71bc6a7cc25/ILI9341_t3.h#L124-L142
// colors
// void QrCode_Task (void *arg) {
// while (1) {
// timerQrCode.loop();
// vTaskDelay(500 / portTICK_PERIOD_MS);
// }
// }
// void QrCodeCheck_Task (void *arg) {
// while (1) {
// timerQrCodeCheck.loop();
// vTaskDelay(2500 / portTICK_PERIOD_MS);
// }
// }
// void Ok_Task (void *arg) {
// while (1) {
// timerOk.loop();
// vTaskDelay(500 / portTICK_PERIOD_MS);
// }
// }
void setup () {
BEGIN();
btnOkLongPress.onSinglePress(onButtonOkLongPressed);
btnOk.onSinglePress(onButtonOkPressed);
btnCancel.onSinglePress(onButtonCancelPressed);
timerOk.onTick(onTimerOkTicked);
timerOk.onFinish(onTimerOkFinished);
timerQrCode.onTick(onTimerQrCodeTicked);
timerQrCode.onFinish(onTimerQrCodeFinished);
timerQrCodeCheck.onTick(onTimerQrCodeCheckTicked);
timerConfirm.onTick(onTimerConfirmTicked);
timerConfirm.onFinish(onTimerConfirmFinished);
timerCancel.onTick(onTimerCancelTicked);
timerCancel.onFinish(onTimerCancelFinished);
timerWifiSta.onTick(onTimerWifiStaTicked);
tft.begin();
tft.setRotation(2);
tft.setFont(NULL);
tft.setTextSize(2);
tft.setTextColor(ILI9341_WHITE);
//tft.fillScreen(ILI9341_DARKGREY);
PRINT("QR_VERSION: ");
PRINTLN(QR_VERSION);
// PRINT("LEFT_BORDER: ");
// PRINTLN(LEFT_BORDER);
// PRINT("TOP_BORDER: ");
// PRINTLN(TOP_BORDER);
uint32_t seed1 = random(999999999);
uint32_t seed2 = random(999999999);
PRINT("SEED 1: ");
PRINTLN(seed1);
PRINT("SEED 2: ");
PRINTLN(seed2);
uuid.seed(seed1, seed2);
WiFi.mode(WIFI_AP_STA);
beginStartMode();
// xTaskCreate(QrCode_Task, "QrCode_Task", 100, NULL, 0, NULL);
// xTaskCreate(QrCodeCheck_Task, "QrCodeCheck_Task", 100, NULL, 2, NULL);
// xTaskCreate(Ok_Task, "Ok_Task", 100, NULL, 1, NULL);
}
void loop () {
btnOkLongPress.loop();
btnOk.loop();
btnCancel.loop();
timerWifiSta.loop();
timerQrCode.loop();
timerQrCodeCheck.loop();
timerOk.loop();
timerConfirm.loop();
timerCancel.loop();
buzzer.loop();
pulse.loop();
dnsServer.processNextRequest();
}
Loading
xiao-esp32-c3
xiao-esp32-c3