cryptnox-sdk-esp32 1.0.0
ESP32 SDK for Cryptnox Hardware Wallet
Loading...
Searching...
No Matches
main.cpp
Go to the documentation of this file.
1/*
2 * SPDX-License-Identifier: LGPL-3.0-or-later
3 * Copyright (c) 2026 Cryptnox SA
4 */
5
28
29#include <string.h>
30#include "freertos/FreeRTOS.h"
31#include "freertos/task.h"
32#include "freertos/event_groups.h"
33#include "driver/spi_master.h"
34#include "esp_log.h"
35#include "esp_wifi.h"
36#include "esp_netif.h"
37#include "esp_event.h"
38#include "nvs_flash.h"
39#include "pn532.h"
40#include "CryptnoxWallet.h"
41#include "Pn532NfcTransport.h"
42#include "ESP32Logger.h"
44#include "ESP32Platform.h"
45#include "config.h"
46
47/* ── SPI wiring — ESP32-S3 dev kit + Keyestudio PN532 breakout ──── */
48#define SPI_MOSI 11
49#define SPI_MISO 13
50#define SPI_SCLK 12
51#define SPI_MAX_TRANSFER_SZ 4096
52#define SPI_PIN_UNUSED (-1)
53#define NFC_CS 10
54
55static const char *const TAG = "verify_pin";
56static const uint32_t LOOP_DELAY_MS = 1000U;
57static const uint32_t WIFI_TIMEOUT_MS = 10000U;
58static const int WIFI_MAX_RETRY = 5;
59
60#define WIFI_CONNECTED_BIT BIT0
61#define WIFI_FAIL_BIT BIT1
62
63static EventGroupHandle_t s_wifi_event_group;
64static int s_retry_num = 0;
65
78static void wifi_event_handler(void *arg, esp_event_base_t event_base,
79 int32_t event_id, void *event_data)
80{
81 (void)arg;
82 (void)event_data;
83 if ((event_base == WIFI_EVENT) && (event_id == WIFI_EVENT_STA_START)) {
84 esp_wifi_connect();
85 } else if ((event_base == WIFI_EVENT) &&
86 (event_id == WIFI_EVENT_STA_DISCONNECTED)) {
88 esp_wifi_connect();
90 } else {
91 xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
92 }
93 } else if ((event_base == IP_EVENT) && (event_id == IP_EVENT_STA_GOT_IP)) {
94 s_retry_num = 0;
95 xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
96 } else {
97 /* other events ignored */
98 }
99}
100
113static void wifi_start(void)
114{
115 s_wifi_event_group = xEventGroupCreate();
116 s_retry_num = 0;
117 ESP_ERROR_CHECK(esp_netif_init());
118 ESP_ERROR_CHECK(esp_event_loop_create_default());
119 (void)esp_netif_create_default_wifi_sta();
120 wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
121 ESP_ERROR_CHECK(esp_wifi_init(&cfg));
122 esp_event_handler_instance_t h_any;
123 esp_event_handler_instance_t h_ip;
124 ESP_ERROR_CHECK(esp_event_handler_instance_register(
125 WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL, &h_any));
126 ESP_ERROR_CHECK(esp_event_handler_instance_register(
127 IP_EVENT, IP_EVENT_STA_GOT_IP, &wifi_event_handler, NULL, &h_ip));
128 wifi_config_t wifi_cfg;
129 (void)memset(&wifi_cfg, 0, sizeof(wifi_cfg));
130 (void)strncpy((char *)wifi_cfg.sta.ssid, WIFI_SSID,
131 sizeof(wifi_cfg.sta.ssid) - 1U);
132 (void)strncpy((char *)wifi_cfg.sta.password, WIFI_PASSWORD,
133 sizeof(wifi_cfg.sta.password) - 1U);
134 wifi_cfg.sta.threshold.authmode = WIFI_AUTH_WPA2_PSK;
135 ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
136 ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_cfg));
137 ESP_ERROR_CHECK(esp_wifi_start());
138 EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
140 pdFALSE, pdFALSE,
141 pdMS_TO_TICKS(WIFI_TIMEOUT_MS));
142 if ((bits & WIFI_CONNECTED_BIT) != 0U) {
143 ESP_LOGI(TAG, "WiFi connected");
144 } else {
145 ESP_LOGW(TAG, "WiFi connect failed — TRNG entropy may be reduced");
146 }
147 (void)esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, h_ip);
148 (void)esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, h_any);
149 vEventGroupDelete(s_wifi_event_group);
150}
151
161static void run_verify_pin_loop(CryptnoxWallet &wallet)
162{
163 /* Replace with the PIN set on the card (4–9 ASCII digits). */
164 static const uint8_t DEMO_PIN[CW_MAX_PIN_LENGTH] = {
165 '0', '0', '0', '0', '0', '0', '0', '0', '0'
166 };
167
168 bool keep_running = true;
169 while (keep_running) {
170 CW_SecureSession session{};
171 bool connected = wallet.connect(session);
172
173 if (!connected) {
174 ESP_LOGW(TAG, "Card not detected");
175 }
176
177 if (connected) {
178 bool pinOk = wallet.verifyPin(session,
179 DEMO_PIN,
180 static_cast<uint8_t>(CW_MAX_PIN_LENGTH));
181 if (pinOk) {
182 ESP_LOGI(TAG, "PIN accepted");
183 } else {
184 /* CRITICAL: do NOT retry — each wrong PIN decrements the card's
185 * retry counter. Reaching 0 permanently blocks the PIN.
186 * Fix DEMO_PIN before flashing again. */
187 ESP_LOGE(TAG, "PIN rejected — halting to protect retry counter");
188 keep_running = false;
189 }
190 }
191
192 wallet.disconnect(session);
193
194 if (keep_running) {
195 vTaskDelay(pdMS_TO_TICKS(LOOP_DELAY_MS));
196 }
197 }
198
199 while (true) {
200 vTaskDelay(pdMS_TO_TICKS(LOOP_DELAY_MS));
201 }
202}
203
210extern "C" void app_main(void)
211{
212 esp_err_t nvs_ret = nvs_flash_init();
213 if ((nvs_ret == ESP_ERR_NVS_NO_FREE_PAGES) ||
214 (nvs_ret == ESP_ERR_NVS_NEW_VERSION_FOUND)) {
215 ESP_ERROR_CHECK(nvs_flash_erase());
216 nvs_ret = nvs_flash_init();
217 }
218 ESP_ERROR_CHECK(nvs_ret);
219 wifi_start();
220
221 spi_bus_config_t buscfg = {};
222 buscfg.mosi_io_num = SPI_MOSI;
223 buscfg.miso_io_num = SPI_MISO;
224 buscfg.sclk_io_num = SPI_SCLK;
225 buscfg.quadwp_io_num = SPI_PIN_UNUSED;
226 buscfg.quadhd_io_num = SPI_PIN_UNUSED;
227 buscfg.max_transfer_sz = SPI_MAX_TRANSFER_SZ;
228 ESP_ERROR_CHECK(spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO));
229
230 pn532_t nfc = {};
231 pn532_config_t nfc_cfg = {};
232 nfc_cfg.spi_host = SPI2_HOST;
233 nfc_cfg.pin_cs = NFC_CS;
234 nfc_cfg.skip_bus_init = true;
235 esp_err_t nfc_ret = pn532_init(&nfc, &nfc_cfg);
236
237 if (nfc_ret == ESP_OK) {
238 ESP32Logger logger;
239 (void)logger.begin(115200UL);
240
241 ESP32CryptoProvider cryptoProvider;
242 ESP32Platform platform;
243 Pn532NfcTransport nfcTransport(&nfc, logger);
244 CryptnoxWallet wallet(nfcTransport, logger, cryptoProvider, platform);
245
246 if (wallet.begin()) {
247 run_verify_pin_loop(wallet);
248 } else {
249 ESP_LOGE(TAG, "Wallet init failed");
250 }
251 } else {
252 ESP_LOGE(TAG, "PN532 init failed");
253 }
254}
#define WIFI_SSID
#define WIFI_PASSWORD
#define NFC_CS
Definition main.cpp:59
void app_main(void)
ESP-IDF application entry point.
Definition main.cpp:284
static EventGroupHandle_t s_wifi_event_group
Definition main.cpp:80
#define SPI_MAX_TRANSFER_SZ
Definition main.cpp:57
#define WIFI_FAIL_BIT
Definition main.cpp:78
#define SPI_MOSI
Definition main.cpp:54
#define SPI_PIN_UNUSED
Definition main.cpp:58
static const uint32_t LOOP_DELAY_MS
Definition main.cpp:73
#define SPI_MISO
Definition main.cpp:55
static void wifi_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
FreeRTOS event handler driving the Wi-Fi station state machine.
Definition main.cpp:95
#define WIFI_CONNECTED_BIT
Definition main.cpp:77
static int s_retry_num
Definition main.cpp:81
#define SPI_SCLK
Definition main.cpp:56
static void wifi_start(void)
Initialise Wi-Fi station mode and block until connected or timeout.
Definition main.cpp:130
CW_Logger implementation that writes to ESP32 UART0 via printf.
CW_Platform implementation for ESP32 using FreeRTOS.
CW_NfcTransport adapter wrapping the ESP-IDF PN532 NFC driver.
static void run_verify_pin_loop(CryptnoxWallet &wallet)
Main application loop: connect, verify PIN, and disconnect.
Definition main.cpp:161
CW_CryptoProvider backed by mbedTLS and the ESP32 hardware TRNG.
CW_Logger backed by ESP32 UART0.
Definition ESP32Logger.h:48
bool begin(unsigned long baudRate=115200UL) override
Initialise UART0 at the given baud rate.
CW_Platform backed by FreeRTOS vTaskDelay.
CW_NfcTransport implementation backed by the ESP-IDF PN532 driver.
CW_CryptoProvider implementation for ESP32 using mbedTLS and the hardware TRNG.
static const char *const TAG
#define WIFI_TIMEOUT_MS
Definition eth_rpc.cpp:28
#define WIFI_MAX_RETRY
Definition eth_rpc.cpp:27
esp_err_t pn532_init(pn532_t *dev, const pn532_config_t *config)
Initialise the PN532 and bring it to a ready state.
Definition pn532.c:657
Low-level PN532 NFC controller driver for ESP-IDF (SPI and I²C).
Compile-time configuration passed to pn532_init.
Definition pn532.h:111
spi_host_device_t spi_host
Definition pn532.h:115
bool skip_bus_init
Definition pn532.h:120
Opaque-like runtime state for a single PN532 instance.
Definition pn532.h:141