Skip to content

Lfarsky/nfc/convert to polling#7081

Open
FarskyL wants to merge 21 commits into
mainfrom
lfarsky/nfc/convert_to_polling
Open

Lfarsky/nfc/convert to polling#7081
FarskyL wants to merge 21 commits into
mainfrom
lfarsky/nfc/convert_to_polling

Conversation

@FarskyL

@FarskyL FarskyL commented Jun 8, 2026

Copy link
Copy Markdown

This PR converts NFC RFAL library to be called by sysevent loop.
In prodtest functions the developer must handles only start and stop of NFC discovery + handling of generated NFC events.
For NFC card reader, the RFAL configuration was extracted to const structure.

@FarskyL FarskyL requested a review from kopecdav June 8, 2026 14:25
@FarskyL FarskyL self-assigned this Jun 8, 2026
@FarskyL FarskyL requested a review from TychoVrahe as a code owner June 8, 2026 14:25
@FarskyL FarskyL added the T3W1 Trezor Safe 7 label Jun 8, 2026
@FarskyL FarskyL requested a review from obrusvit as a code owner June 8, 2026 14:25
@FarskyL FarskyL added this to Firmware Jun 8, 2026
@github-project-automation github-project-automation Bot moved this to 🔎 Needs review in Firmware Jun 8, 2026
@coderabbitai

coderabbitai Bot commented Jun 8, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

The NFC public header is refactored to remove technology registration and RFAL STM functions, replacing them with nfc_start_discovery/nfc_stop_discovery, a new nfc_get_state query, and a nfc_transceive with output-pointer RX arguments. New enums (nfc_dev_interface_t, nfc_discovery_type_t) and nfc_state_t struct are added; nfc_event_t is renamed to connected/disconnected semantics. The ST25 driver is refactored around these APIs with a default_disc_params template and a card_connected state flag. A new nfc_poll.c module implements a per-task FSM integrated with the system handle (SYSHANDLE_NFC) for event delivery. The prodtest CLI commands are updated to use the new discovery and sysevent-gated polling APIs. NFC-F and NFC-V RFAL features are disabled.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • trezor/trezor-firmware#6829: Modifies the same prodtest_nfc_read_card, prodtest_nfc_emulate_card, and prodtest_nfc_write_card handlers, updating error reporting to use PRODTEST_ERR_NFC_* codes, which directly intersects with this PR's refactor of those same command loops.

Suggested labels

no-QA

Suggested reviewers

  • TychoVrahe
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Lfarsky/nfc/convert to polling' describes the main change—converting NFC to use the event polling system—though it uses a branch-name-like format and could be more descriptive.
Description check ✅ Passed The description clearly explains the PR's purpose: converting NFC RFAL to use sysevent loop, requiring prodtest functions to handle discovery start/stop and events, and extracting RFAL configuration to a const structure.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch lfarsky/nfc/convert_to_polling

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown

en main(all)

model device_test click_test persistence_test
T2T1 test(all) main(all) test(all) main(all) test(all) main(all)
T3B1 test(all) main(all) test(all) main(all) test(all) main(all)
T3T1 test(all) main(all) test(all) main(all) test(all) main(all)
T3W1 test(all) main(all) test(all) main(all) test(all) main(all)

Latest CI run: 28371043993

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
core/embed/io/nfc/st25/nfc.c (1)

642-679: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Type mismatch: nfc_transcieve_blocking returns nfc_status_t, not ReturnCode.

The variable err is declared as ReturnCode (line 643), but nfc_transcieve_blocking returns nfc_status_t. The loop condition compares against RFAL_ERR_NONE and RFAL_ERR_SLEEP_REQ:

  • NFC_OK == 0 and RFAL_ERR_NONE == 0 — this works by coincidence
  • RFAL_ERR_SLEEP_REQ will never match any nfc_status_t return value, so sleep-request handling is broken

This could cause the card emulator loop to exit prematurely or behave incorrectly when a sleep request occurs.

Proposed fix: Use correct type and status values
 static void nfc_card_emulator_loop(rfalNfcDevice *nfc_dev) {
-  ReturnCode err = RFAL_ERR_INTERNAL;
+  nfc_status_t status = NFC_ERROR;
   uint8_t *rx_buf;
   uint16_t *rcv_len;
   uint8_t tx_buf[150];
   uint16_t tx_len;

   do {
     rfalNfcWorker();

     switch (rfalNfcGetState()) {
       case RFAL_NFC_STATE_ACTIVATED:
-        err = nfc_transcieve_blocking(NULL, 0, &rx_buf, &rcv_len, 0);
+        status = nfc_transcieve_blocking(NULL, 0, &rx_buf, &rcv_len, 0);
         break;

       case RFAL_NFC_STATE_DATAEXCHANGE:
       case RFAL_NFC_STATE_DATAEXCHANGE_DONE:

         tx_len =
             ((nfc_dev->type == RFAL_NFC_POLL_TYPE_NFCA)
                  ? card_emulation_t4t(rx_buf, *rcv_len, tx_buf, sizeof(tx_buf))
                  : rfalConvBytesToBits(
                        card_emulation_t3t(rx_buf, rfalConvBitsToBytes(*rcv_len),
                                           tx_buf, sizeof(rx_buf))));

-        err = nfc_transcieve_blocking(tx_buf, tx_len, &rx_buf, &rcv_len,
+        status = nfc_transcieve_blocking(tx_buf, tx_len, &rx_buf, &rcv_len,
                                       RFAL_FWT_NONE);
         break;

       case RFAL_NFC_STATE_START_DISCOVERY:
         return;

       case RFAL_NFC_STATE_LISTEN_SLEEP:
       default:
         break;
     }
-  } while ((err == RFAL_ERR_NONE) || (err == RFAL_ERR_SLEEP_REQ));
+  } while (status == NFC_OK);
 }

Note: If sleep-request handling is needed, nfc_transcieve_blocking should be extended to return a distinct status for that case, or the loop should check RFAL state directly for sleep conditions.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@core/embed/io/nfc/st25/nfc.c` around lines 642 - 679, The loop uses
ReturnCode err but nfc_transcieve_blocking returns nfc_status_t, so replace the
err declaration/type in nfc_card_emulator_loop with nfc_status_t and update the
loop condition to compare against the correct nfc_status_t constants (e.g.,
NFC_OK and the nfc sleep-request constant, e.g., NFC_SLEEP_REQ) instead of
RFAL_ERR_NONE/RFAL_ERR_SLEEP_REQ; keep references to nfc_transcieve_blocking,
nfc_card_emulator_loop, and rx_buf/tx_buf logic intact (alternatively, if sleep
handling should be driven by RFAL state, check rfalNfcGetState() for the sleep
state rather than using RFAL_* error codes).
🧹 Nitpick comments (6)
core/embed/io/nfc/st25/nfc.c (1)

471-481: ⚡ Quick win

Variable declarations inside switch case should use braces.

Declaring variables directly inside a case label without braces can lead to initialization issues if the code is modified later (e.g., adding fallthrough cases). Wrap the case body in braces for safety.

Proposed fix
   switch (dev_info.type) {
-    case NFC_DEV_TYPE_A:
-      uint8_t rxBuf[20];
-      uint16_t rxLen = sizeof(rxBuf);
-      ReturnCode err = rfalT2TPollerRead(0x00, rxBuf, sizeof(rxBuf), &rxLen);
-      return err == RFAL_ERR_NONE;
+    case NFC_DEV_TYPE_A: {
+      uint8_t rxBuf[20];
+      uint16_t rxLen = sizeof(rxBuf);
+      ReturnCode err = rfalT2TPollerRead(0x00, rxBuf, sizeof(rxBuf), &rxLen);
+      return err == RFAL_ERR_NONE;
+    }
     case NFC_DEV_TYPE_B:
     case NFC_DEV_TYPE_V:
     default:
       return false;
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@core/embed/io/nfc/st25/nfc.c` around lines 471 - 481, The switch case for
NFC_DEV_TYPE_A declares local variables (rxBuf, rxLen, err) without braces; wrap
the NFC_DEV_TYPE_A case body in braces so the declarations are scoped correctly,
e.g., put a { ... } around the code that calls rfalT2TPollerRead and returns its
result, ensuring rxBuf, rxLen and err are declared inside that block and the
return err == RFAL_ERR_NONE; remains unchanged.
core/embed/io/nfc/inc/io/nfc.h (1)

82-87: ⚡ Quick win

Consider using nfc_dev_type_t instead of uint8_t for the type field.

The type field is declared as uint8_t but stores values from nfc_dev_type_t enum. Using the enum type directly would improve type safety and make the API self-documenting.

Proposed fix
 typedef struct {
-  uint8_t type;
+  nfc_dev_type_t type;
   nfc_dev_interface_t interface;
   char uid[NFC_MAX_UID_BUF_SIZE];  // Plus one for string termination
   uint8_t uid_len;
 } nfc_dev_info_t;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@core/embed/io/nfc/inc/io/nfc.h` around lines 82 - 87, The struct
nfc_dev_info_t uses a plain uint8_t for the type field even though values come
from the nfc_dev_type_t enum; change the field declaration from uint8_t type to
nfc_dev_type_t type to improve type safety and self-documentation, and update
any code that constructs or assigns to nfc_dev_info_t.type to use the enum
values (or cast where unavoidable); ensure the header that defines
nfc_dev_type_t is visible (include or forward-declare) so the compilation
remains correct.
core/embed/io/nfc/st25/nfc_poll.c (2)

76-79: ⚡ Quick win

Add bounds check for task_id.

The task_id parameter is used as an array index into g_nfc_tls without validation. While the system event framework should only call this with valid task IDs, adding a defensive bounds check would prevent potential out-of-bounds access if the contract changes.

🛡️ Proposed fix
 static void on_task_created(void* context, systask_id_t task_id) {
+  if (task_id >= SYSTASK_MAX_TASKS) {
+    return;
+  }
   nfc_fsm_t* fsm = &g_nfc_tls[task_id];
   memset(fsm, 0, sizeof(nfc_fsm_t));
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@core/embed/io/nfc/st25/nfc_poll.c` around lines 76 - 79, The on_task_created
callback uses task_id directly to index g_nfc_tls which can cause out-of-bounds
access; add a defensive bounds check at the start of on_task_created to verify
task_id is within the valid range for g_nfc_tls (e.g., compare against the array
length/maximum task count constant), and only then obtain nfc_fsm_t* fsm =
&g_nfc_tls[task_id] and call memset; if task_id is invalid, return early
(optionally log or assert) to avoid touching g_nfc_tls.

116-123: ⚡ Quick win

Add parameter validation.

The function directly casts param to nfc_state_t* (Line 120) and uses task_id as an array index (Line 118) without validation. While the system event framework contract should guarantee valid values, adding defensive checks would improve robustness.

🛡️ Proposed fix
 static bool on_check_read_ready(void* context, systask_id_t task_id,
                                 void* param) {
+  if (task_id >= SYSTASK_MAX_TASKS || param == NULL) {
+    return false;
+  }
   nfc_fsm_t* fsm = &g_nfc_tls[task_id];
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@core/embed/io/nfc/st25/nfc_poll.c` around lines 116 - 123, The
on_check_read_ready function lacks defensive checks: validate task_id before
indexing g_nfc_tls (ensure task_id < ARRAY_SIZE(g_nfc_tls) or other valid range)
and validate param is non-NULL (and optionally that it points to a valid
nfc_state_t) before casting; if checks fail, return false (or an appropriate
error) instead of performing the cast/index and call nfc_fsm_update only after
validations pass.
core/embed/io/nfc/st25/nfc_poll.h (1)

20-26: ⚡ Quick win

Consider adding detailed module documentation.

The current comment at Line 22 provides a brief description but lacks important details that would help consumers use this module correctly:

  • Initialization order requirements (must call nfc_poll_init() after nfc_init())
  • Threading model (which functions are safe to call from which contexts)
  • Relationship to system event framework (requires SYSHANDLE_NFC registration)
  • Usage pattern (call nfc_get_event() after sysevents_poll() signals SYSHANDLE_NFC read-ready)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@core/embed/io/nfc/st25/nfc_poll.h` around lines 20 - 26, Add comprehensive
module-level documentation above the declarations in nfc_poll.h: state that
nfc_poll_init() must be called only after nfc_init(), describe the
threading/ISR/context model and which functions are safe to call from task vs
interrupt contexts (including nfc_poll_deinit()), document the dependency on the
system event framework and that SYSHANDLE_NFC must be registered, and show the
typical usage pattern (call sysevents_poll(), wait for SYSHANDLE_NFC read-ready,
then call nfc_get_event() / related APIs). Mention return/errno behavior for
nfc_poll_init() and nfc_poll_deinit() and any lifetime/ordering constraints
between nfc_poll_init(), nfc_poll_deinit(), and nfc_init()/nfc_shutdown.
core/embed/io/nfc/st25/nfc_poll_internal.h (1)

27-33: ⚡ Quick win

Consider adding function documentation.

The internal API functions lack documentation comments explaining their purpose, parameters, return values, and preconditions. This would help maintainers understand the contract between the polling module and the NFC driver implementation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@core/embed/io/nfc/st25/nfc_poll_internal.h` around lines 27 - 33, Add
Doxygen-style documentation comments above each internal API declaration
(nfc_is_connected, nfc_identify, nfc_check_connection, nfc_restart_discovery)
that state the function purpose, parameters (e.g., device_type for
nfc_identify), return values and meaning, preconditions (required state before
calling), side effects, and any thread-safety/ownership guarantees; place the
comments in the header near the declarations so callers and implementers can
read the contract for the polling module and NFC driver implementation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@core/embed/io/nfc/st25/nfc_poll.c`:
- Around line 51-57: nfc_get_event dereferences the pointer parameter `event`
without validation; add a NULL check at the start of nfc_get_event and return
false if event is NULL to avoid a null-pointer dereference. Locate the function
nfc_get_event and before accessing *event, verify `if (event == NULL) return
false;` then proceed to use fsm (g_nfc_tls and systask_id(systask_active())) and
set *event and clear fsm->events as existing code does.

In `@core/embed/io/nfc/st25/nfc.c`:
- Around line 431-446: The nfc_identify(rfalNfcDevType device_type) function
currently ignores its device_type parameter and instead uses
nfc_dev_read_info(&dev_info). Either remove the unused parameter from the
function signature and update its declaration in the header and every call site
(e.g., the call from nfc_poll.c) to match the new signature, or modify
nfc_identify to use the passed device_type by comparing device_type against
NFC_DEV_TYPE_A/B/V (or combining both checks: verify device_type matches
dev_info.type) and keep the signature. Update the prototype in the header and
all callers to ensure consistency.

In `@core/embed/projects/prodtest/cmd/prodtest_nfc.c`:
- Around line 124-138: The switch on dev_info.interface currently treats unknown
interfaces as an error; add an explicit case for NFC_DEV_INTERFACE_UNKNOWN in
the same switch (the block switching on dev_info.interface with cases
NFC_DEV_INTERFACE_RF, NFC_DEV_INTERFACE_ISODEP, NFC_DEV_INTERFACE_NFCDEP) and
handle it gracefully (e.g., call cli_trace(cli, "NFC Tag Type: UNKNOWN (%d)",
dev_info.interface)) instead of letting it fall through to the default that
calls cli_error and goto cleanup; leave the default case to report truly
unexpected values as before.

---

Outside diff comments:
In `@core/embed/io/nfc/st25/nfc.c`:
- Around line 642-679: The loop uses ReturnCode err but nfc_transcieve_blocking
returns nfc_status_t, so replace the err declaration/type in
nfc_card_emulator_loop with nfc_status_t and update the loop condition to
compare against the correct nfc_status_t constants (e.g., NFC_OK and the nfc
sleep-request constant, e.g., NFC_SLEEP_REQ) instead of
RFAL_ERR_NONE/RFAL_ERR_SLEEP_REQ; keep references to nfc_transcieve_blocking,
nfc_card_emulator_loop, and rx_buf/tx_buf logic intact (alternatively, if sleep
handling should be driven by RFAL state, check rfalNfcGetState() for the sleep
state rather than using RFAL_* error codes).

---

Nitpick comments:
In `@core/embed/io/nfc/inc/io/nfc.h`:
- Around line 82-87: The struct nfc_dev_info_t uses a plain uint8_t for the type
field even though values come from the nfc_dev_type_t enum; change the field
declaration from uint8_t type to nfc_dev_type_t type to improve type safety and
self-documentation, and update any code that constructs or assigns to
nfc_dev_info_t.type to use the enum values (or cast where unavoidable); ensure
the header that defines nfc_dev_type_t is visible (include or forward-declare)
so the compilation remains correct.

In `@core/embed/io/nfc/st25/nfc_poll_internal.h`:
- Around line 27-33: Add Doxygen-style documentation comments above each
internal API declaration (nfc_is_connected, nfc_identify, nfc_check_connection,
nfc_restart_discovery) that state the function purpose, parameters (e.g.,
device_type for nfc_identify), return values and meaning, preconditions
(required state before calling), side effects, and any thread-safety/ownership
guarantees; place the comments in the header near the declarations so callers
and implementers can read the contract for the polling module and NFC driver
implementation.

In `@core/embed/io/nfc/st25/nfc_poll.c`:
- Around line 76-79: The on_task_created callback uses task_id directly to index
g_nfc_tls which can cause out-of-bounds access; add a defensive bounds check at
the start of on_task_created to verify task_id is within the valid range for
g_nfc_tls (e.g., compare against the array length/maximum task count constant),
and only then obtain nfc_fsm_t* fsm = &g_nfc_tls[task_id] and call memset; if
task_id is invalid, return early (optionally log or assert) to avoid touching
g_nfc_tls.
- Around line 116-123: The on_check_read_ready function lacks defensive checks:
validate task_id before indexing g_nfc_tls (ensure task_id <
ARRAY_SIZE(g_nfc_tls) or other valid range) and validate param is non-NULL (and
optionally that it points to a valid nfc_state_t) before casting; if checks
fail, return false (or an appropriate error) instead of performing the
cast/index and call nfc_fsm_update only after validations pass.

In `@core/embed/io/nfc/st25/nfc_poll.h`:
- Around line 20-26: Add comprehensive module-level documentation above the
declarations in nfc_poll.h: state that nfc_poll_init() must be called only after
nfc_init(), describe the threading/ISR/context model and which functions are
safe to call from task vs interrupt contexts (including nfc_poll_deinit()),
document the dependency on the system event framework and that SYSHANDLE_NFC
must be registered, and show the typical usage pattern (call sysevents_poll(),
wait for SYSHANDLE_NFC read-ready, then call nfc_get_event() / related APIs).
Mention return/errno behavior for nfc_poll_init() and nfc_poll_deinit() and any
lifetime/ordering constraints between nfc_poll_init(), nfc_poll_deinit(), and
nfc_init()/nfc_shutdown.

In `@core/embed/io/nfc/st25/nfc.c`:
- Around line 471-481: The switch case for NFC_DEV_TYPE_A declares local
variables (rxBuf, rxLen, err) without braces; wrap the NFC_DEV_TYPE_A case body
in braces so the declarations are scoped correctly, e.g., put a { ... } around
the code that calls rfalT2TPollerRead and returns its result, ensuring rxBuf,
rxLen and err are declared inside that block and the return err ==
RFAL_ERR_NONE; remains unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0a8537d2-a64b-433f-94a3-dbff15c88901

📥 Commits

Reviewing files that changed from the base of the PR and between bc28535 and 5b01d49.

📒 Files selected for processing (9)
  • core/embed/io/nfc/inc/io/nfc.h
  • core/embed/io/nfc/st25/nfc.c
  • core/embed/io/nfc/st25/nfc_poll.c
  • core/embed/io/nfc/st25/nfc_poll.h
  • core/embed/io/nfc/st25/nfc_poll_internal.h
  • core/embed/projects/prodtest/cmd/prodtest_nfc.c
  • core/embed/projects/prodtest/main.c
  • core/embed/sys/task/inc/sys/sysevent.h
  • core/site_scons/models/T3W1/trezor_t3w1_revC.py

Comment on lines +51 to +57
bool nfc_get_event(nfc_event_t* event) {
nfc_fsm_t* fsm = &g_nfc_tls[systask_id(systask_active())];

*event = fsm->events;
fsm->events = NFC_NO_EVENT;
return true;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add NULL check for the event parameter.

The function dereferences event at Line 54 without validating it. If a caller passes NULL, this will cause a null-pointer dereference.

🛡️ Proposed fix
 bool nfc_get_event(nfc_event_t* event) {
+  if (event == NULL) {
+    return false;
+  }
   nfc_fsm_t* fsm = &g_nfc_tls[systask_id(systask_active())];
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@core/embed/io/nfc/st25/nfc_poll.c` around lines 51 - 57, nfc_get_event
dereferences the pointer parameter `event` without validation; add a NULL check
at the start of nfc_get_event and return false if event is NULL to avoid a
null-pointer dereference. Locate the function nfc_get_event and before accessing
*event, verify `if (event == NULL) return false;` then proceed to use fsm
(g_nfc_tls and systask_id(systask_active())) and set *event and clear
fsm->events as existing code does.

Comment thread core/embed/io/nfc/st25/nfc.c Outdated
Comment thread core/embed/projects/prodtest/cmd/prodtest_nfc.c
@FarskyL FarskyL force-pushed the lfarsky/nfc/convert_to_polling branch from 5b01d49 to 61ba401 Compare June 9, 2026 06:45

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@core/embed/io/nfc/st25/nfc_poll_internal.h`:
- Around line 27-31: Update the zero-argument function declarations and
implementations to use C's explicit void parameter list: change the prototypes
for nfc_is_connected, nfc_identify, and nfc_check_connection to use (void)
instead of empty () in the header, and modify the corresponding implementations
of nfc_is_connected and nfc_check_connection in the source (which currently use
empty ()) to also use (void) so signatures match nfc_identify(void) and enable
proper call-arity checking.

In `@core/embed/io/nfc/st25/nfc.c`:
- Around line 274-275: The waiting loop inside nfc_stop_discovery() that spins
until RFAL_NFC_STATE_IDLE must be bounded: replace the infinite wait with a
timed/iteration-bounded wait (e.g., check a monotonic timeout or max-iteration
counter) and if the timeout expires, break out, log an error, and perform a safe
fallback (abort the RFAL transition or force poll deinit) and return a failure
code so callers (e.g., nfc_deinit()) can handle it; apply the same bounded-wait
pattern to the other similar loop referenced in the review (the other stop/wait
loop around RFAL_NFC_STATE_IDLE) so both nfc_stop_discovery() and the deinit
path no longer hang on stuck RFAL transitions.
- Around line 96-98: The current poll configuration (.techs2Find includes
RFAL_NFC_POLL_TECH_B and _V) advertises Type B/V support but
nfc_check_connection() only implements a Type A liveness check, causing B/V
cards to immediately disconnect via nfc_restart_discovery(); either implement
proper B and V presence checks inside nfc_check_connection() (handle
RFAL_NFC_POLL_TECH_B and RFAL_NFC_POLL_TECH_V paths and use the appropriate RFAL
presence APIs) or remove RFAL_NFC_POLL_TECH_B/_V from the .techs2Find mask so
they are not advertised; ensure you update or validate related logic in
nfc_identify() and the poll configuration (techs2Find/techs2Bail) so the
cross-file contract between the poll configuration and nfc_check_connection() is
consistent.
- Around line 312-316: The code sets drv->disc_params.GBLen to the backing array
size (sizeof(default_disc_params.GB)) which can advertise trailing zeros; change
it to use the configured payload length (e.g. default_disc_params.GBLen or the
actual populated length) instead. Locate the assignment to
drv->disc_params.GBLen and replace the sizeof(...) usage with the configured GB
length constant/field from default_disc_params so the driver advertises only the
valid General Bytes. Ensure any memcpy or transmit logic that relies on GBLen
uses this length variable.

In `@core/embed/projects/prodtest/main.c`:
- Around line 207-209: The nfc_init() call in the driver startup ignores its
return value; update the startup code that calls nfc_init() (the nfc_init
invocation in main) to check its return status, and on failure log an explicit
error (including any error code/message), abort startup or return a non-zero
error from main (or set a clear "NFC unavailable" state) so the CLI cannot
proceed with a broken NFC subsystem; ensure the change covers both the `#ifdef`
USE_NFC path and any cleanup path (e.g., skip poll registration) so failures are
diagnosed immediately.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: eedef743-2717-48e5-bcb2-1fc8929b5b46

📥 Commits

Reviewing files that changed from the base of the PR and between 5b01d49 and 61ba401.

📒 Files selected for processing (9)
  • core/embed/io/nfc/inc/io/nfc.h
  • core/embed/io/nfc/st25/nfc.c
  • core/embed/io/nfc/st25/nfc_poll.c
  • core/embed/io/nfc/st25/nfc_poll.h
  • core/embed/io/nfc/st25/nfc_poll_internal.h
  • core/embed/projects/prodtest/cmd/prodtest_nfc.c
  • core/embed/projects/prodtest/main.c
  • core/embed/sys/task/inc/sys/sysevent.h
  • core/site_scons/models/T3W1/trezor_t3w1_revC.py
✅ Files skipped from review due to trivial changes (1)
  • core/embed/io/nfc/st25/nfc_poll.h
🚧 Files skipped from review as they are similar to previous changes (5)
  • core/embed/sys/task/inc/sys/sysevent.h
  • core/site_scons/models/T3W1/trezor_t3w1_revC.py
  • core/embed/projects/prodtest/cmd/prodtest_nfc.c
  • core/embed/io/nfc/st25/nfc_poll.c
  • core/embed/io/nfc/inc/io/nfc.h

Comment thread core/embed/io/nfc/st25/nfc_poll_internal.h Outdated
Comment thread core/embed/io/nfc/st25/nfc.c Outdated
Comment thread core/embed/io/nfc/st25/nfc.c
Comment thread core/embed/io/nfc/st25/nfc.c Outdated
Comment thread core/embed/projects/prodtest/main.c Outdated
Comment on lines +207 to +209
#ifdef USE_NFC
nfc_init();
#endif

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Handle nfc_init() failure explicitly in driver startup.

At Line 208, the return value is ignored. If NFC init/poll registration fails, startup proceeds silently and failures appear later in CLI flow with poor diagnosability.

Proposed fix
 `#ifdef` USE_NFC
-  nfc_init();
+  nfc_status_t nfc_status = nfc_init();
+  if (nfc_status != NFC_OK) {
+    // keep booting prodtest, but surface root-cause early
+    cli_trace(&g_cli, "NFC init failed: %d", nfc_status);
+  }
 `#endif`
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@core/embed/projects/prodtest/main.c` around lines 207 - 209, The nfc_init()
call in the driver startup ignores its return value; update the startup code
that calls nfc_init() (the nfc_init invocation in main) to check its return
status, and on failure log an explicit error (including any error code/message),
abort startup or return a non-zero error from main (or set a clear "NFC
unavailable" state) so the CLI cannot proceed with a broken NFC subsystem;
ensure the change covers both the `#ifdef` USE_NFC path and any cleanup path
(e.g., skip poll registration) so failures are diagnosed immediately.

@FarskyL FarskyL force-pushed the lfarsky/nfc/convert_to_polling branch from 61ba401 to 8695ae0 Compare June 9, 2026 10:40
Comment thread core/embed/io/nfc/inc/io/nfc.h Outdated
} nfc_dev_info_t;

// Initialize NFC driver including supportive RFAL middleware
// Initialize NFC driver including supportive RFAL middleware and polling

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should take opportunity to update the public api docu format to recent "doxygen like" structure. You can see example in 'power_manager.h' for instance.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed d565b90

Comment thread core/embed/io/nfc/st25/nfc.c Outdated
typedef struct {
bool initialized;
bool rfal_initialized;
bool card_connected;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This flag seems to be duplicate to the connected state defined in nfc_state_t used in nfc_poll, the state should has only one single source of truth. nfc_get_state function and nfc_get_event should be using it.

Comment thread core/embed/io/nfc/st25/nfc.c Outdated
Comment thread core/embed/io/nfc/inc/io/nfc.h Outdated
NFC_DEV_TYPE_ST25TB,
NFC_DEV_TYPE_AP2P,
NFC_DEV_TYPE_POLL_TYPE_A,
NFC_DEV_TYPE_POLL_TYPE_F,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets keep NFC_DEV_TYPE_A and B only, please cleanup all other variables and configuration options in other places and disable unused technologies in rfal_platform.h

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed a957d91

Comment thread core/embed/io/nfc/inc/io/nfc.h Outdated
NFC_OK = 0,
NFC_ERROR,
NFC_WRONG_STATE,
NFC_PARAM,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

whole nfc_status_t is somehow obsolete now. We should refactor whole driver with ts_t status codes defined in error_handling.h. You can look into haptic driver for reference.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed d565b90

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, looks good, just please also replace classical status checks with TSH_CHECK macros.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed in 67bb665

Comment thread core/embed/projects/prodtest/main.c Outdated
Comment thread core/embed/projects/prodtest/cmd/prodtest_nfc.c Outdated
Comment thread core/embed/io/nfc/st25/nfc.c Outdated
@github-project-automation github-project-automation Bot moved this from 🔎 Needs review to 🏃‍♀️ In progress in Firmware Jun 15, 2026
@FarskyL FarskyL force-pushed the lfarsky/nfc/convert_to_polling branch from f1a4a23 to 5be328f Compare June 19, 2026 11:57
@FarskyL FarskyL force-pushed the lfarsky/nfc/convert_to_polling branch from 5be328f to 304f365 Compare June 19, 2026 12:22
@FarskyL FarskyL force-pushed the lfarsky/nfc/convert_to_polling branch from 304f365 to bff6414 Compare June 19, 2026 12:45
Comment thread core/embed/io/nfc/st25/nfc.c Outdated
default:
*event = NFC_NO_EVENT;
}
bool nfc_is_connected() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add void into argument

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed 27c9685

Comment thread core/embed/io/nfc/st25/nfc.c Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All those NFC-F defines and LM_SEL_RES is not used anymore, could be removed

@FarskyL FarskyL Jun 26, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry, forgotten during the cleanup :)
f37d56f

Comment thread core/embed/io/nfc/st25/nfc.c Outdated
if (err != RFAL_ERR_NONE) {
return NFC_ERROR;
}
nfc_status_t err = nfc_transcieve_blocking(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo in transceive.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed b35a061

Comment thread core/embed/io/nfc/inc/io/nfc.h Outdated
void nfc_get_state(nfc_state_t *state);

// Read the general device information of the activated NFC device.
nfc_status_t nfc_dev_read_info(nfc_dev_info_t *dev_info);

@kopecdav kopecdav Jun 25, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should remove nfc_dev_write_ndef_uri functions from this layer and use nfc_transceive function instead in upper layer to read/write ndef .. Right now this may limit us to T4T devices, but for now should be fine.

@FarskyL FarskyL Jun 29, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed f318efa76ed15bf76f41ab246f56e7e2cd28fdc2

Comment thread core/embed/io/nfc/inc/io/nfc.h Outdated

// Read the general device information of the activated NFC device.
nfc_status_t nfc_dev_read_info(nfc_dev_info_t *dev_info);
/** @brief Read the general device information of the activated NFC device. */

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should also add parameters and return value context into the doc

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed e1aa816

Comment thread core/embed/io/nfc/inc/io/nfc.h Outdated
bool nfc_get_event(nfc_event_t *event);

/** @brief Get current state of NFC device. */
void nfc_get_state(nfc_state_t *state);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should keep nfc_get_state function, this is essential since it should come in a pair with nfc_get_event function . It may be placed in the nfc_poll.c to conveniently connect it to state evaluated there. Also we should keep to define the state in the header file to be publicly available.

I would rather remove the connected flag in the internal nfc handler.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed 2dab336

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed 2dab336

@FarskyL FarskyL force-pushed the lfarsky/nfc/convert_to_polling branch from e1aa816 to 2dab336 Compare June 29, 2026 08:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

T3W1 Trezor Safe 7

Projects

Status: 🏃‍♀️ In progress

Development

Successfully merging this pull request may close these issues.

3 participants