cryptnox-pos 1.0.0
Standalone USDC payment terminal firmware (ESP32 + Cryptnox smart card)
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
14
15
16#include "pos_app.h"
17
18/* The main loop wakes at least this often with nothing to do, so it can feed the
19 * task watchdog (CONFIG_ESP_TASK_WDT_TIMEOUT_S is 60). */
20#define MAIN_LOOP_TICK_MS 5000U
21#define HEAP_LOG_PERIOD_US (10LL * 60LL * 1000000LL)
22
23QueueHandle_t s_ui_queue = NULL;
24
25/* Set by the UI task on Cancel during PLACE_CARD; the main task checks it after
26 * signing to skip the FAILED flash. Atomic because it crosses tasks. */
27std::atomic<bool> s_user_cancelled{false};
28
39void ui_event_dispatch(ui_event_t event, uint64_t payload) {
40 if (event == UI_EVENT_CONFIRM_CANCEL) {
41 s_user_cancelled = true;
42 }
43 ui_msg_t msg = { event, payload };
44 (void)xQueueSend(s_ui_queue, &msg, 0);
45}
46
51extern "C" void app_main(void)
52{
53 const pos_hw_t hw = pos_boot();
54 CryptnoxWallet &wallet = hw.wallet;
55 Pn532NfcTransport &nfcTransport = hw.transport;
56 CW_CryptoProvider &cryptoProvider = hw.crypto;
57
58 /* ── Main interaction loop ────────────────────────────────── */
59 /* A sale that was between broadcast and verdict when the terminal went down
60 * (brownout, panic, somebody pulling the plug) is picked up where it stopped:
61 * same hash, same checks, and the verdict on the panel — Unconfirmed with
62 * "Check again" if the network is not back yet. */
63 if (settings_inflight_load(&s_inflight, sizeof(s_inflight)) && s_inflight.active) {
64 ESP_LOGW(TAG, "resuming the sale in flight at reset: %s", s_inflight.hash);
66 } else {
69 }
70
71 pos_amount_t pending_amount;
72 pos_amount_set(&pending_amount, 0U);
73 ui_msg_t msg;
74
75 /* A card read from the admin page yields both addresses, but the panel shows
76 * one proposal at a time: the Tron one waits here until the Ethereum one is
77 * resolved, and the restart that applies a stored address waits for both. */
78 char card_tron[SETTINGS_PAYOUT_MAX] = "";
79 bool restart_due = false;
80
81 /* On the task watchdog from here on: a loop that stops coming back to its
82 * queue is a hung terminal, and resetting it beats a frozen panel. Boot above
83 * is not subscribed — the wizard and the picker wait on people. */
84 if (esp_task_wdt_add(NULL) != ESP_OK) {
85 ESP_LOGE(TAG, "main loop not on the task watchdog");
86 }
87 int64_t next_heap_log_us = esp_timer_get_time() + HEAP_LOG_PERIOD_US;
88
89 while (true) {
90 wdt_feed();
91 /* Heap fragmentation is the likely way TLS handshakes start failing after
92 * days (fresh handshake per call, no PSRAM); log it every ten minutes. */
93 if (esp_timer_get_time() >= next_heap_log_us) {
94 next_heap_log_us = esp_timer_get_time() + HEAP_LOG_PERIOD_US;
95 ESP_LOGI(TAG, "heap: %u free, %u largest block",
96 static_cast<unsigned>(esp_get_free_heap_size()),
97 static_cast<unsigned>(
98 heap_caps_get_largest_free_block(MALLOC_CAP_DEFAULT)));
99 }
100 if (xQueueReceive(s_ui_queue, &msg, pdMS_TO_TICKS(MAIN_LOOP_TICK_MS)) != pdTRUE) {
101 continue;
102 }
103
104 switch (msg.event) {
106 pos_amount_set(&pending_amount, msg.payload);
107 /* Refuse before the customer taps: offline, every request the sale
108 * makes would fail after the card and PIN; without a clock TLS
109 * cannot validate a certificate. */
110 if (!net_wifi_online() || (wall_ms() == 0U)) {
113 ? "Offline - re-joining the Wi-Fi"
114 : "Waiting for network time");
115 pos_amount_set(&pending_amount, 0U);
116 break;
117 }
118 /* Refuse rather than fall back. settings_get_payout() answers with
119 * the config.h recipient when nobody set one, which would send a
120 * customer's money to an address the operator never chose while
121 * looking entirely normal. A till never told where the money goes
122 * declines the sale, as it does for an unset token contract. */
125 "Payout address not configured");
126 pos_amount_set(&pending_amount, 0U);
127 break;
128 }
129 /* Set, but it failed the checksum at boot: the dual store holds
130 * the config.h fallback, which nobody chose for this till. */
131 if (s_payout_bad[chain_is_tron() ? 1 : 0]) {
133 "Payout address invalid - set it again");
134 pos_amount_set(&pending_amount, 0U);
135 break;
136 }
137 const token_t *tok = active_token();
138 /* Say so here rather than after the customer has tapped a card:
139 * a placeholder contract means this asset was never set up. */
140 if ((tok != NULL) && !tok->ok) {
142 "Token contract not configured");
143 pos_amount_set(&pending_amount, 0U);
144 break;
145 }
146 char dec_err[64];
148 sizeof(dec_err))) {
150 pos_amount_set(&pending_amount, 0U);
151 break;
152 }
153 /* Reconcile amount + recipient (+ token contract) before they
154 * are shown to the customer — displayed value must equal what
155 * gets signed. */
156 if (!IS_TRUE32(amount_consistent(&pending_amount)) ||
158 ((tok != NULL) &&
160 pos_handle_anomaly("pre-display reconcile");
161 ui_show_tx_status(UI_TX_STATE_FAILED, "Integrity check failed");
162 pos_amount_set(&pending_amount, 0U);
163 break;
164 }
165 /* No balance check here: the payer is the card, and nobody has
166 * tapped yet. evm_balance_ok / tron_balance_ok run once it is
167 * present. */
169 /* Show the resolved recipient, NOT the config.h literal: they
170 * differ on a terminal provisioned through the setup page, and the
171 * operator checks the address against this row. s_payout_* is the
172 * string s_dest / s_tron_dest were parsed from, so what is
173 * displayed is what gets signed. */
175 &s_sale_fee.prio_fee);
176 char fee_txt[40];
177 sale_fee_text(fee_txt, sizeof(fee_txt));
178 ui_show_confirm(pending_amount.amount_minor,
180 fee_txt);
181 break;
182 }
183
186 break;
187
189 if (pending_amount.amount_minor == 0U) {
190 /* No fresh AMOUNT_CONFIRMED preceded this — likely a stale
191 * event from a stuck touch or queue replay. Drop it. */
192 ESP_LOGW(TAG, "stale PIN_ENTERED ignored");
193 break;
194 }
195 /* Fetch the keypad PIN (UI wipes its own copy on read). */
196 char pin[16] = { 0 };
197 size_t pin_chars = ui_take_pin(pin, sizeof(pin));
198
199 s_user_cancelled = false;
200 char err_msg[64] = { 0 };
201 inflight_t *fl = &s_inflight;
202 CW_Utils::secure_wipe(reinterpret_cast<uint8_t *>(fl), sizeof(*fl));
203 /* The decided amount, for the final gate — in the record before
204 * the sign, because the record is persisted before the broadcast
205 * (inflight_persist) and a resumed poll needs it too. */
206 fl->decided = pending_amount;
207 const bcast_t sent =
208 pay_sign_and_broadcast(wallet, nfcTransport, cryptoProvider,
209 &pending_amount, pin, pin_chars, fl,
210 err_msg, sizeof(err_msg));
211 /* scrub our copy of the PIN as soon as signing is done. */
212 CW_Utils::secure_wipe(reinterpret_cast<uint8_t *>(pin), sizeof(pin));
213
214 /* Clear pending so the next sign needs a fresh New Payment flow. */
215 pos_amount_set(&pending_amount, 0U);
216 if (sent != BCAST_FAILED) {
217 /* Out of our hands now, whatever the cancel flag says: a
218 * signed transaction the node may hold is settled by the
219 * chain, not by a tap on the panel. */
220 fl->active = true;
221 fl->broadcast_known = (sent == BCAST_SENT);
223 } else if (!s_user_cancelled) {
224 settings_inflight_clear(); /* refused: nothing went out */
226 } else {
227 /* Cancelled — before the broadcast, so nothing went out
228 * either; drop any record so a reboot does not resume it. */
230 /* Cancel during PLACE_CARD — UI already on amount entry. */
231 }
232 break;
233 }
234
236 /* "Check again" on the Unconfirmed screen: same sale, same hash. */
237 if (s_inflight.active) {
239 } else {
241 }
242 break;
243
245 /* New sale — or, from Unconfirmed, the operator's explicit
246 * "I have checked" Clear. The record goes either way: the nonce
247 * is read from "latest", so if the old one is still pending a
248 * new sale replaces it rather than landing beside it. */
249 s_inflight.active = false;
252 break;
253
255 /* Run here, not on the UI task: prov_stop() blocks for up to ~2 s
256 * and would freeze the panel. */
257 if (prov_mode() != PROV_MODE_OFF) { prov_stop(); }
258 break;
259
261 /* Uploaded and verified firmware; nothing boots until it is
262 * accepted on the panel. Routed through this queue so the offer
263 * waits behind a payment rather than appearing over one. */
265 break;
266
267 /* ── The admin page, open beside a running terminal ──
268 * Same handlers as the wizard's, and for the same reason: a browser may
269 * propose, only the panel may accept. Routed through this queue so an
270 * offer waits behind a payment in progress rather than appearing over
271 * a customer's transaction. */
274 break;
275
277 ui_show_prov_confirm(); /* decimals: see token_decimals_ok */
278 break;
279
282 if (msg.event == UI_EVENT_PROV_VALUE_SET) { restart_due = true; }
283 /* The panel slot is free again: offer the parked Tron address. */
284 if (card_tron[0] != '\0') {
285 (void)prov_propose(PROV_ASK_PAYOUT_TRON, card_tron);
286 card_tron[0] = '\0';
287 break;
288 }
289 if (!restart_due) { break; }
290 /* Stored. The recipient and contract dual stores are built at boot
291 * from validated strings, so the change applies through a restart
292 * rather than a second, re-validating path into the money code. */
293 ESP_LOGW(TAG, "config changed from the admin page - restarting");
294 prov_stop();
295 ui_set_boot_status("Applying settings");
296 vTaskDelay(pdMS_TO_TICKS(600));
297 esp_restart();
298 break;
299
300 case UI_EVENT_PROV_CARD: {
301 /* Same flow as the wizard: PIN on the keypad, tap, then the
302 * accept-on-the-panel handshake. */
303 s_user_cancelled = false;
304 prov_set_note("Follow the terminal screen.");
306 break;
307 }
308
309 case UI_EVENT_CARD_PIN: {
310 char pin[16] = { 0 };
311 size_t pin_chars = ui_take_pin(pin, sizeof(pin));
312 char c_eth[SETTINGS_PAYOUT_MAX] = "";
313 char c_tron[SETTINGS_PAYOUT_MAX] = "";
314 char err[48] = { 0 };
315 const bool got = card_read_payouts(wallet, nfcTransport,
316 cryptoProvider,
317 pin, pin_chars,
318 c_eth, sizeof(c_eth),
319 c_tron, sizeof(c_tron),
320 err, sizeof(err));
321 CW_Utils::secure_wipe(reinterpret_cast<uint8_t *>(pin), sizeof(pin));
322 if (!got) {
323 /* No setup screen mid-shift: show the reason on the failure
324 * screen rather than dropping silently back to the keypad. */
325 prov_set_note(err);
327 break;
328 }
330 prov_set_note("Accept each address on the terminal screen.");
331 /* Ethereum first if there is one; Tron waits in card_tron and is
332 * offered when that proposal is resolved (see PROV_VALUE_SET). */
333 card_tron[0] = '\0';
334 if (c_eth[0] != '\0') {
335 (void)prov_propose(PROV_ASK_PAYOUT_ETH, c_eth);
336 (void)snprintf(card_tron, sizeof(card_tron), "%s", c_tron);
337 } else if (c_tron[0] != '\0') {
338 (void)prov_propose(PROV_ASK_PAYOUT_TRON, c_tron);
339 }
340 break;
341 }
342
343 case UI_EVENT_PROV_SCAN: {
344 net_wifi_ap_t aps[16];
345 const uint16_t n_aps = net_wifi_scan(aps, 16);
346 prov_set_scan(aps, n_aps);
347 break;
348 }
349
350 case UI_EVENT_WIFI_SCAN: {
351 /* Scan runs in this task so the UI stays responsive. */
352 net_wifi_ap_t aps[16];
353 uint16_t n = net_wifi_scan(aps, 16);
354 /* Opened from settings, not after a failure — no note. */
355 ui_show_wifi_list(aps, n, NULL);
356 break;
357 }
358
359 case UI_EVENT_WIFI_TRY: {
360 char w_ssid[33] = { 0 };
361 char w_pass[65] = { 0 };
362 if (ui_take_wifi_creds(w_ssid, sizeof(w_ssid),
363 w_pass, sizeof(w_pass)) > 0U) {
365
366 /* Same rule as boot: associating proves nothing, so a clock
367 * sync must prove the uplink before saved credentials are
368 * overwritten. One round only; the operator can tap again. */
369 const char *why = NULL;
370 if (!net_wifi_connect(w_ssid, w_pass)) {
371 why = NOTE_JOIN_FAILED;
372 } else if (!net_time_sync(15000U)) {
373 ESP_LOGW(TAG, "'%s' joined but has no network time -"
374 " not saved", w_ssid);
375 why = NOTE_NO_TIME;
376 } else {
377 settings_set_wifi(w_ssid, w_pass); /* persist for next boot */
378 /* From the config page: the terminal must never be on a
379 * network *and* serving that page (httpd binds every
380 * interface), so close it rather than hand the forms to
381 * the new LAN. */
382 if (prov_mode() != PROV_MODE_OFF) { prov_stop(); }
384 }
385
386 if (why != NULL) {
387 /* The radio is still on the rejected network, so the
388 * terminal would look ready while every payment fails.
389 * Roll back to the saved network boot already proved. */
390 char b_ssid[33] = { 0 };
391 char b_pass[65] = { 0 };
392 if (settings_get_wifi(b_ssid, sizeof(b_ssid),
393 b_pass, sizeof(b_pass)) &&
394 (b_ssid[0] != '\0')) {
395 ESP_LOGW(TAG, "rolling back to saved network '%s'",
396 b_ssid);
398 if (!net_wifi_connect(b_ssid, b_pass) &&
399 (prov_mode() == PROV_MODE_OFF)) {
400 /* The saved network is down too; keep retrying
401 * it in the background. */
403 }
404 }
405 CW_Utils::secure_wipe(
406 reinterpret_cast<uint8_t *>(b_pass), sizeof(b_pass));
407
408 /* prov_stop() re-joins with the restored credentials, but
409 * no association may stay up while the config page is
410 * served: drop it, back to AP-only. */
412
413 /* Back to the picker with the reason, so another network
414 * can be chosen instead of a dead end. */
415 net_wifi_ap_t aps[16];
416 uint16_t n = net_wifi_scan(aps, 16);
417 ui_show_wifi_list(aps, n, why);
418 }
419 }
420 CW_Utils::secure_wipe(reinterpret_cast<uint8_t *>(w_pass), sizeof(w_pass));
421 break;
422 }
423
424 default:
425 break;
426 }
427 }
428}
pos_hw_t pos_boot(void)
Everything before the main loop. Returns the card stack, which lives for the life of the program.
Definition boot.cpp:496
const char *const NOTE_NO_TIME
Definition boot.cpp:60
const char *const NOTE_JOIN_FAILED
Definition boot.cpp:58
bool card_read_payouts(CryptnoxWallet &wallet, Pn532NfcTransport &transport, CW_CryptoProvider &crypto, const char *pin, size_t pin_chars, char *eth_out, size_t eth_n, char *tron_out, size_t tron_n, char *err, size_t err_n)
Read the card's payout addresses and put them through the panel.
Definition card_io.cpp:233
static const char *const TAG
Definition eth_rpc.cpp:33
void pos_handle_anomaly(const char *where)
Report an anomaly: bump a self-checked persisted counter, log it, and keep a local ring buffer for on...
Definition hardening.cpp:99
#define IS_TRUE32(x)
Definition hardening.h:43
static bool32 amount_consistent(const pos_amount_t *a)
Definition hardening.h:93
static bool32 address_consistent(const pos_addr_t *a)
Definition hardening.h:98
static void pos_amount_set(pos_amount_t *a, uint64_t v)
Write both amount stores from one value (two independent writes).
Definition hardening.h:70
#define HEAP_LOG_PERIOD_US
Definition main.cpp:21
QueueHandle_t s_ui_queue
Definition main.cpp:23
std::atomic< bool > s_user_cancelled
Definition main.cpp:27
void app_main(void)
ESP-IDF application entry point: bring-up, then the main interaction loop (amount → confirm → sign+br...
Definition main.cpp:51
#define MAIN_LOOP_TICK_MS
Definition main.cpp:20
void ui_event_dispatch(ui_event_t event, uint64_t payload)
UI-task callback: forward a touch event to the main task queue.
Definition main.cpp:39
void net_wifi_disconnect(void)
Drop the station association, without the retry loop pulling it back.
Definition net.cpp:268
void net_wifi_keep_trying(void)
Hold on to the network last configured, even though it is down now.
Definition net.cpp:430
bool net_time_sync(uint32_t timeout_ms)
Block until the system clock has been set via SNTP and sanity-checked.
Definition net.cpp:536
bool net_wifi_online(void)
true while the station holds an IP address.
Definition net.cpp:437
bool net_wifi_connect(const char *ssid, const char *password)
Connect to a WiFi network and block until an IP is obtained (up to 30 s). May be called repeatedly to...
Definition net.cpp:376
uint16_t net_wifi_scan(net_wifi_ap_t *out, uint16_t max)
Scan for nearby access points (blocking).
Definition net.cpp:322
token_t * active_token(pos_chain_t chain)
The selection's token, or NULL for a native coin.
Definition pay.cpp:45
char s_payout_tron[SETTINGS_PAYOUT_MAX]
Definition pay.cpp:28
uint64_t wall_ms(void)
Unix time in ms, 0 while the clock is unset.
Definition pay.cpp:237
sale_fee_t s_sale_fee
Definition pay.cpp:192
bool token_decimals_ok(pos_chain_t chain, char *err, size_t err_max)
Before the first sale in an operator-set token, read its decimals() and refuse anything but 6.
Definition pay.cpp:115
bcast_t pay_sign_and_broadcast(CryptnoxWallet &wallet, Pn532NfcTransport &transport, CW_CryptoProvider &crypto, const pos_amount_t *amount, const char *pin, size_t pin_chars, inflight_t *fl, char *err_out, size_t err_max)
Sign and broadcast the reconciled sale on whichever family is selected. The family is read once,...
Definition pay.cpp:347
void sale_fee_text(char *out, size_t n)
The most network fee the customer's card can be charged on top of the sale, for the confirm screen....
Definition pay.cpp:201
void ui_refresh_addresses(void)
Implemented by main: repoint those two rows at the selected chain.
Definition pay.cpp:170
void settle_inflight(void)
Poll the in-flight sale for up to 120 s and show what the chain says.
Definition pay.cpp:255
const pos_addr_t * active_dest(void)
The reconciled recipient for the chain currently selected.
Definition pay.cpp:188
inflight_t s_inflight
Definition pay.cpp:219
bool s_payout_bad[2]
Definition pay.cpp:182
char s_payout_eth[SETTINGS_PAYOUT_MAX]
Definition pay.cpp:27
void evm_fees_wei(bool polygon, uint64_t *max_fee, uint64_t *prio_fee)
The EIP-1559 fees one EVM sale will offer, in wei per gas.
Definition pay_evm.cpp:64
Private to the application files (main, boot, card_io, pay, pay_evm, pay_tron): the state they share ...
static bool chain_is_tron(void)
true when the operator has switched the terminal to Tron.
Definition pos_app.h:74
bcast_t
Definition pos_app.h:148
@ BCAST_FAILED
Definition pos_app.h:149
@ BCAST_SENT
Definition pos_app.h:150
static bool chain_is_polygon(void)
true when the terminal is charging on Polygon rather than Ethereum.
Definition pos_app.h:79
void prov_set_note(const char *note)
Put a one-line message on the page.
bool prov_propose(prov_ask_t kind, const char *addr)
Propose a value on behalf of the panel itself.
prov_mode_t prov_mode(void)
Which mode is running, or PROV_MODE_OFF.
void prov_stop(void)
Stop the portal, drop the AP, and withdraw anything unaccepted.
void prov_set_scan(const net_wifi_ap_t *aps, uint16_t n)
Hand the portal a Wi-Fi scan for the browser to choose from.
@ PROV_ASK_PAYOUT_TRON
Definition provision.h:131
@ PROV_ASK_PAYOUT_ETH
Definition provision.h:130
@ PROV_MODE_OFF
Definition provision.h:105
bool settings_get_wifi(char *ssid, size_t ssid_n, char *pass, size_t pass_n)
Read the stored Wi-Fi credentials.
Definition settings.cpp:298
pos_chain_t settings_get_chain(void)
Selected chain, or POS_CHAIN_ETH_USDC if never set.
Definition settings.cpp:165
void settings_set_wifi(const char *ssid, const char *pass)
Persist Wi-Fi credentials (plaintext — see README threat model).
Definition settings.cpp:324
bool settings_inflight_load(void *rec, size_t n)
Read the persisted sale back. false if none, or not n bytes.
Definition settings.cpp:660
void settings_inflight_clear(void)
Drop the persisted sale. Writes nothing when there is none.
Definition settings.cpp:673
bool settings_has_payout(bool tron)
Whether an operator has actually set the payout address for a network.
Definition settings.cpp:534
#define SETTINGS_PAYOUT_MAX
Longest payout address plus NUL — "0x" + 40 hex, or 34 base58 Tron.
Definition settings.h:214
bool active
Definition pos_app.h:158
pos_amount_t decided
Definition pos_app.h:169
bool broadcast_known
Definition pos_app.h:167
A scanned access point (subset of fields the UI needs).
Definition net.h:33
uint64_t amount_minor
Definition hardening.h:59
The card stack pos_boot() brought up; lives for the program.
Definition pos_app.h:252
CryptnoxWallet & wallet
Definition pos_app.h:253
CW_CryptoProvider & crypto
Definition pos_app.h:255
Pn532NfcTransport & transport
Definition pos_app.h:254
A token's contract, dual-stored.
Definition pos_app.h:98
pos_addr_t addr
Definition pos_app.h:100
bool ok
Definition pos_app.h:101
ui_event_t event
Definition pos_app.h:241
uint64_t payload
Definition pos_app.h:242
void ui_show_confirm(uint64_t amount_units, const char *dest_addr, const char *fee)
Switch to the confirm screen.
Definition ui.cpp:718
void ui_show_prov_auth(void)
Demand the admin code so a browser can be authorised.
Definition ui.cpp:861
void ui_set_boot_status(const char *step)
Set the one-line progress note on the splash screen.
Definition ui.cpp:776
void ui_show_wifi_list(const net_wifi_ap_t *aps, uint16_t n, const char *note)
Show the scanned Wi-Fi networks for the user to pick from.
Definition ui.cpp:747
void ui_show_card_pin(void)
Ask for the card PIN before reading an address off a Cryptnox card.
Definition ui.cpp:873
void ui_show_ota_confirm(void)
Raise the modal that asks the operator to accept a firmware image the update page has uploaded,...
Definition ui.cpp:893
size_t ui_take_wifi_creds(char *ssid, size_t ssid_n, char *pass, size_t pass_n)
Fetch the selected SSID + entered password and wipe the UI's copy.
Definition ui.cpp:827
void ui_show_tx_status(ui_tx_state_t state, const char *info)
Switch to the transaction-status screen.
Definition ui.cpp:898
void ui_show_amount_entry(void)
Switch to the amount-entry screen (forces a value redraw).
Definition ui.cpp:711
void ui_show_prov_confirm(void)
Raise the modal that asks the operator to accept a value a browser proposed, reading the pending prop...
Definition ui.cpp:856
void ui_show_wifi_connecting(const char *ssid)
Show a "Connecting to <ssid>…" screen while main associates.
Definition ui.cpp:770
size_t ui_take_pin(char *out, size_t n)
Copy the most recently entered PIN out and wipe the UI's copy.
Definition ui.cpp:733
@ UI_TX_STATE_FAILED
Definition ui.h:101
ui_event_t
Events emitted by the UI task towards the main task.
Definition ui.h:55
@ UI_EVENT_CONFIRM_CANCEL
Definition ui.h:58
@ UI_EVENT_PIN_ENTERED
Definition ui.h:59
@ UI_EVENT_OTA_STAGED
Definition ui.h:82
@ UI_EVENT_PROV_AUTH
Definition ui.h:66
@ UI_EVENT_CARD_PIN
Definition ui.h:80
@ UI_EVENT_WIFI_TRY
Definition ui.h:61
@ UI_EVENT_PROV_VALUE_NO
Definition ui.h:71
@ UI_EVENT_AMOUNT_CONFIRMED
Definition ui.h:56
@ UI_EVENT_WIFI_SCAN
Definition ui.h:60
@ UI_EVENT_PROV_CARD
Definition ui.h:75
@ UI_EVENT_PROV_VALUE
Definition ui.h:68
@ UI_EVENT_PROV_SCAN
Definition ui.h:77
@ UI_EVENT_PROV_STOP
Definition ui.h:86
@ UI_EVENT_TX_RETRY
Definition ui.h:62
@ UI_EVENT_PROV_VALUE_SET
Definition ui.h:70
@ UI_EVENT_TX_RECHECK
Definition ui.h:84
static void wdt_feed(void)
Feed the task watchdog if, and only if, the calling task is subscribed.
Definition wdt.h:28