mirror of
https://github.com/solokeys/solo2.git
synced 2026-06-20 13:16:13 -07:00
ctap2.3: nrf52840dk runner with ML-DSA-44 + CTAPHID keepalive support
This commit is contained in:
committed by
Emanuele Cesena
parent
bcbb14f7a8
commit
01727ccd7a
Generated
+155
@@ -110,6 +110,12 @@ version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
||||
|
||||
[[package]]
|
||||
name = "az"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be5eb007b7cacc6c660343e96f650fedf4b5a77512399eb952ca6642cf8d13f7"
|
||||
|
||||
[[package]]
|
||||
name = "bare-metal"
|
||||
version = "0.2.5"
|
||||
@@ -220,12 +226,24 @@ version = "3.20.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb"
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck"
|
||||
version = "1.25.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "cast"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
|
||||
|
||||
[[package]]
|
||||
name = "cbc"
|
||||
version = "0.1.2"
|
||||
@@ -718,6 +736,15 @@ dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "embedded-dma"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "994f7e5b5cb23521c22304927195f236813053eb9c065dd2226a32ba64695446"
|
||||
dependencies = [
|
||||
"stable_deref_trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "embedded-hal"
|
||||
version = "0.2.7"
|
||||
@@ -754,6 +781,12 @@ dependencies = [
|
||||
"embedded-hal-async",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "embedded-storage"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a21dea9854beb860f3062d10228ce9b976da520a73474aed3171ec276bc0c032"
|
||||
|
||||
[[package]]
|
||||
name = "embedded-time"
|
||||
version = "0.12.1"
|
||||
@@ -832,6 +865,18 @@ version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
|
||||
|
||||
[[package]]
|
||||
name = "fixed"
|
||||
version = "1.31.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9af2cbf772fa6d1c11358f92ef554cb6b386201210bcf0e91fb7fba8a907fb40"
|
||||
dependencies = [
|
||||
"az",
|
||||
"bytemuck",
|
||||
"half",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flexiber"
|
||||
version = "0.1.3"
|
||||
@@ -1610,6 +1655,68 @@ dependencies = [
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nrf-hal-common"
|
||||
version = "0.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "089242b8b729622099054dcb5518e9eac80bcf6a7e30091c7cfa043383e9998c"
|
||||
dependencies = [
|
||||
"cast",
|
||||
"cfg-if",
|
||||
"cortex-m",
|
||||
"embedded-dma",
|
||||
"embedded-hal 0.2.7",
|
||||
"embedded-storage",
|
||||
"fixed",
|
||||
"nb 1.1.0",
|
||||
"nrf-usbd",
|
||||
"nrf52840-pac",
|
||||
"rand_core 0.6.4",
|
||||
"void",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nrf-nfc"
|
||||
version = "2.2281.0"
|
||||
dependencies = [
|
||||
"cortex-m",
|
||||
"cty",
|
||||
"defmt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nrf-usbd"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "945a178131ac5f69941dadb0d51c8e17cbe34cc09a0e2d51c099160a463751b8"
|
||||
dependencies = [
|
||||
"cortex-m",
|
||||
"usb-device",
|
||||
"vcell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nrf52840-hal"
|
||||
version = "0.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "71c090616930ef132c1f7e9f9a964f6c8c5aa8962e402cc5abbbde7ce16ce9a0"
|
||||
dependencies = [
|
||||
"embedded-hal 0.2.7",
|
||||
"nrf-hal-common",
|
||||
"nrf52840-pac",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nrf52840-pac"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9efa9d1e910e3b825fd7e28f369363a8e036b386b77e21035b9f0e510de199cf"
|
||||
dependencies = [
|
||||
"cortex-m",
|
||||
"cortex-m-rt",
|
||||
"vcell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-ansi-term"
|
||||
version = "0.50.3"
|
||||
@@ -2264,6 +2371,54 @@ dependencies = [
|
||||
"usbd-serial",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "runner-nrf52840dk"
|
||||
version = "2.2281.0"
|
||||
dependencies = [
|
||||
"admin-app",
|
||||
"apdu-dispatch 0.4.0",
|
||||
"cortex-m",
|
||||
"cortex-m-rt",
|
||||
"ctaphid-dispatch",
|
||||
"defmt",
|
||||
"defmt-rtt",
|
||||
"embedded-hal 0.2.7",
|
||||
"embedded-storage",
|
||||
"embedded-time",
|
||||
"fido-authenticator",
|
||||
"generic-array 0.14.7",
|
||||
"heapless 0.9.2",
|
||||
"interchange 0.3.2",
|
||||
"littlefs2",
|
||||
"ndef-app",
|
||||
"nrf-nfc",
|
||||
"nrf-usbd",
|
||||
"nrf52840-hal",
|
||||
"nrf52840-pac",
|
||||
"opcard",
|
||||
"panic-halt",
|
||||
"piv-authenticator",
|
||||
"rtic",
|
||||
"rtic-monotonics",
|
||||
"rtic-sync",
|
||||
"secrets-app",
|
||||
"static_cell",
|
||||
"trussed",
|
||||
"trussed-auth",
|
||||
"trussed-auth-backend",
|
||||
"trussed-chunked",
|
||||
"trussed-core",
|
||||
"trussed-fs-info",
|
||||
"trussed-hkdf",
|
||||
"trussed-hpke",
|
||||
"trussed-manage",
|
||||
"trussed-staging",
|
||||
"trussed-wrap-key-to-file",
|
||||
"usb-device",
|
||||
"usbd-ccid",
|
||||
"usbd-ctaphid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "1.1.0"
|
||||
|
||||
+9
-4
@@ -2,16 +2,16 @@
|
||||
members = [
|
||||
"runners/lpc55",
|
||||
"runners/lpc55/board",
|
||||
"runners/nrf52840dk",
|
||||
"runners/pc",
|
||||
"components/ndef-app",
|
||||
"components/nfc-device",
|
||||
"components/fm11nc08",
|
||||
"components/nrf-nfc",
|
||||
"components/provisioner-app",
|
||||
]
|
||||
# Host-buildable members only. The lpc55 runner/board, fm11nc08, and
|
||||
# provisioner-app (via lpc55-hal) / nfc-device (via embedded deps) all require an
|
||||
# ARM target and can't link on the host, so they're excluded from default
|
||||
# commands like `cargo test`.
|
||||
# Host-buildable members only. The lpc55 / nrf52840dk runners and the
|
||||
# embedded-only components require an ARM target and can't link on the host.
|
||||
default-members = [
|
||||
"runners/pc",
|
||||
"components/ndef-app",
|
||||
@@ -33,6 +33,7 @@ board = { path = "runners/lpc55/board" }
|
||||
ndef-app = { path = "components/ndef-app" }
|
||||
fm11nc08 = { path = "components/fm11nc08" }
|
||||
nfc-device = { path = "components/nfc-device" }
|
||||
nrf-nfc = { path = "components/nrf-nfc" }
|
||||
provisioner-app = { path = "components/provisioner-app" }
|
||||
|
||||
# ── RTIC framework ────────────────────────────────────────────────────────────
|
||||
@@ -128,9 +129,13 @@ p256 = { version = "0.13", features = ["ecdh"] }
|
||||
codegen-units = 1
|
||||
lto = true
|
||||
opt-level = "z"
|
||||
panic = "abort"
|
||||
incremental = false
|
||||
debug = true
|
||||
|
||||
[profile.dev]
|
||||
panic = "abort"
|
||||
|
||||
[profile.release.package.salty]
|
||||
opt-level = 2
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
[package]
|
||||
name = "nrf-nfc"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
authors.workspace = true
|
||||
description = "nRF52840 NFC stack: nrfx_nfct chip layer + libnfc_t4t.a Type 4 Tag library + Rust platform glue"
|
||||
links = "nrf_nfc"
|
||||
|
||||
[lib]
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
cortex-m = { workspace = true }
|
||||
cty = "0.2"
|
||||
defmt = { workspace = true }
|
||||
@@ -0,0 +1,206 @@
|
||||
# Re-build the vendored static libraries + bindgen output for the
|
||||
# nrf-nfc crate. Normal builds don't need this — `cargo build` reads
|
||||
# the committed artifacts in vendor/ directly.
|
||||
#
|
||||
# Run `make regen` when bumping nrfx (the chip layer's source) or when
|
||||
# Nordic ships a new libnfc_t4t.a (the closed-source blob in
|
||||
# vendor/lib/libnfc_t4t.a — copy it in by hand from upstream nrfxlib
|
||||
# first, then run regen to refresh the bindgen output).
|
||||
#
|
||||
# Requires: arm-none-eabi-gcc (in PATH) + bindgen-cli
|
||||
# (cargo install bindgen-cli).
|
||||
|
||||
# Pinned commits for the upstream sources we regenerate libnrfx_nfct.a
|
||||
# from. Bump these together when upgrading the nrfx stack.
|
||||
NRFX_COMMIT := aa83d4df8d5f41b591f23a8555794632afb3475d
|
||||
CMSIS_COMMIT := f6226079fdb207e945dae7cea2c273ea5200376a
|
||||
|
||||
VENDOR := vendor
|
||||
BUILD := .regen-build
|
||||
|
||||
.PHONY: regen regen-clean
|
||||
|
||||
regen: regen-nrfx regen-t4t
|
||||
|
||||
regen-clean:
|
||||
rm -rf $(BUILD)
|
||||
|
||||
# ── Embedded glue header bodies ──────────────────────────────────────────────
|
||||
#
|
||||
# These four headers are project-specific config nrfx requires at C
|
||||
# compile + bindgen time. They live here (not in the crate tree)
|
||||
# because the crate tree should contain only what the *normal* build
|
||||
# needs, which doesn't include any C compilation. The regen target
|
||||
# materializes them in $(BUILD)/glue, uses them, then leaves them for
|
||||
# the next regen run (gitignored).
|
||||
|
||||
define NRFX_CONFIG_H_BODY
|
||||
#ifndef NRFX_CONFIG_H__
|
||||
#define NRFX_CONFIG_H__
|
||||
#ifndef NRF52840_XXAA
|
||||
#define NRF52840_XXAA
|
||||
#endif
|
||||
#define NRFX_NFCT_ENABLED 1
|
||||
#define NRFX_NFCT_CONFIG_TIMER_INSTANCE_ID 4
|
||||
#define NRFX_NFCT_CONFIG_IRQ_PRIORITY 6
|
||||
#define NRFX_NFCT_CONFIG_LOG_ENABLED 0
|
||||
#define NRFX_TIMER_ENABLED 1
|
||||
#define NRFX_TIMER4_ENABLED 1
|
||||
#define NRFX_TIMER_DEFAULT_CONFIG_FREQUENCY 0
|
||||
#define NRFX_TIMER_DEFAULT_CONFIG_MODE 0
|
||||
#define NRFX_TIMER_DEFAULT_CONFIG_BIT_WIDTH 0
|
||||
#define NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY 6
|
||||
#define NRFX_TIMER_CONFIG_LOG_ENABLED 0
|
||||
#include <nrfx_config_common.h>
|
||||
#endif
|
||||
endef
|
||||
export NRFX_CONFIG_H_BODY
|
||||
|
||||
define NRFX_GLUE_H_BODY
|
||||
#ifndef NRFX_GLUE_H__
|
||||
#define NRFX_GLUE_H__
|
||||
#include <nrfx.h>
|
||||
#define NRFX_ASSERT(e) ((void)(e))
|
||||
#define NRFX_STATIC_ASSERT(e) _Static_assert(e, #e)
|
||||
#define NRFX_IRQ_PRIORITY_SET(i, p) NVIC_SetPriority((IRQn_Type)(i), p)
|
||||
#define NRFX_IRQ_ENABLE(i) NVIC_EnableIRQ((IRQn_Type)(i))
|
||||
#define NRFX_IRQ_IS_ENABLED(i) (NVIC_GetEnableIRQ((IRQn_Type)(i)) != 0)
|
||||
#define NRFX_IRQ_DISABLE(i) NVIC_DisableIRQ((IRQn_Type)(i))
|
||||
#define NRFX_IRQ_PENDING_SET(i) NVIC_SetPendingIRQ((IRQn_Type)(i))
|
||||
#define NRFX_IRQ_PENDING_CLEAR(i) NVIC_ClearPendingIRQ((IRQn_Type)(i))
|
||||
#define NRFX_IRQ_IS_PENDING(i) (NVIC_GetPendingIRQ((IRQn_Type)(i)) != 0)
|
||||
extern uint8_t nrfx_critical_section_enter(void);
|
||||
extern void nrfx_critical_section_exit(uint8_t saved);
|
||||
#define NRFX_CRITICAL_SECTION_ENTER() { uint8_t _nrfx_cs = nrfx_critical_section_enter();
|
||||
#define NRFX_CRITICAL_SECTION_EXIT() nrfx_critical_section_exit(_nrfx_cs); }
|
||||
extern void nrfx_delay_us(uint32_t us);
|
||||
#define NRFX_DELAY_US(us) nrfx_delay_us(us)
|
||||
#define NRFX_ATOMIC_FETCH_STORE(p, v) __atomic_exchange_n(p, v, __ATOMIC_SEQ_CST)
|
||||
#define NRFX_ATOMIC_FETCH_OR(p, v) __atomic_fetch_or(p, v, __ATOMIC_SEQ_CST)
|
||||
#define NRFX_ATOMIC_FETCH_AND(p, v) __atomic_fetch_and(p, v, __ATOMIC_SEQ_CST)
|
||||
#define NRFX_ATOMIC_FETCH_XOR(p, v) __atomic_fetch_xor(p, v, __ATOMIC_SEQ_CST)
|
||||
#define NRFX_ATOMIC_FETCH_ADD(p, v) __atomic_fetch_add(p, v, __ATOMIC_SEQ_CST)
|
||||
#define NRFX_ATOMIC_FETCH_SUB(p, v) __atomic_fetch_sub(p, v, __ATOMIC_SEQ_CST)
|
||||
#define NRFX_ATOMIC_CAS(p, ov, nv) ({ __typeof__(ov) _o = (ov); __atomic_compare_exchange_n(p, &_o, nv, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); })
|
||||
#define NRFX_CLZ(v) __builtin_clz(v)
|
||||
#define NRFX_CTZ(v) __builtin_ctz(v)
|
||||
#define NRFX_POPCOUNT(v) __builtin_popcount(v)
|
||||
#define NRFX_EVENT_READBACK_ENABLED 1
|
||||
#define NRFX_DPPI_CHANNELS_USED 0
|
||||
#define NRFX_DPPI_GROUPS_USED 0
|
||||
#define NRFX_PPI_CHANNELS_USED 0
|
||||
#define NRFX_PPI_GROUPS_USED 0
|
||||
#define NRFX_GPIOTE_CHANNELS_USED 0
|
||||
#define NRFX_EGUS_USED 0
|
||||
#define NRFX_TIMERS_USED 0
|
||||
#define NRFX_CUSTOM_ERROR_CODES 0
|
||||
#endif
|
||||
endef
|
||||
export NRFX_GLUE_H_BODY
|
||||
|
||||
define NRFX_LOG_H_BODY
|
||||
#ifndef NRFX_LOG_H__
|
||||
#define NRFX_LOG_H__
|
||||
#define NRFX_LOG_INFO(...) ((void)0)
|
||||
#define NRFX_LOG_WARNING(...) ((void)0)
|
||||
#define NRFX_LOG_ERROR(...) ((void)0)
|
||||
#define NRFX_LOG_DEBUG(...) ((void)0)
|
||||
#define NRFX_LOG_HEXDUMP_INFO(p, len) ((void)0)
|
||||
#define NRFX_LOG_HEXDUMP_WARNING(p,len) ((void)0)
|
||||
#define NRFX_LOG_HEXDUMP_ERROR(p, len) ((void)0)
|
||||
#define NRFX_LOG_HEXDUMP_DEBUG(p, len) ((void)0)
|
||||
#define NRFX_LOG_ERROR_STRING_GET(c) ""
|
||||
#endif
|
||||
endef
|
||||
export NRFX_LOG_H_BODY
|
||||
|
||||
define NRFX_WRAPPER_H_BODY
|
||||
#include <nrfx.h>
|
||||
#include <nrfx_nfct.h>
|
||||
#include <nrfx_timer.h>
|
||||
endef
|
||||
export NRFX_WRAPPER_H_BODY
|
||||
|
||||
define T4T_WRAPPER_H_BODY
|
||||
#define NRF52840_XXAA
|
||||
#include <nfc_t4t_lib.h>
|
||||
#include <nrf_nfc_errno.h>
|
||||
endef
|
||||
export T4T_WRAPPER_H_BODY
|
||||
|
||||
# nrfx include flags reused by both compile + bindgen invocations.
|
||||
NRFX_INCLUDES = \
|
||||
-I$(BUILD)/glue \
|
||||
-I$(BUILD)/cmsis/CMSIS/Core/Include \
|
||||
-I$(BUILD)/nrfx/drivers/include \
|
||||
-I$(BUILD)/nrfx/hal -I$(BUILD)/nrfx/haly \
|
||||
-I$(BUILD)/nrfx/helpers -I$(BUILD)/nrfx/templates \
|
||||
-I$(BUILD)/nrfx/bsp/stable -I$(BUILD)/nrfx/bsp/stable/mdk \
|
||||
-I$(BUILD)/nrfx/bsp/stable/soc -I$(BUILD)/nrfx/bsp/stable/soc/irqs \
|
||||
-I$(BUILD)/nrfx/bsp/stable/soc/interconnect \
|
||||
-I$(BUILD)/nrfx/bsp/stable/templates -I$(BUILD)/nrfx
|
||||
|
||||
# ── regen-nrfx ──────────────────────────────────────────────────────────────
|
||||
#
|
||||
# Compile libnrfx_nfct.a from upstream sources + regenerate
|
||||
# nrfx_nfct_bindings.rs.
|
||||
regen-nrfx: $(BUILD)/nrfx/.git $(BUILD)/cmsis/.git
|
||||
@command -v arm-none-eabi-gcc >/dev/null || { echo "arm-none-eabi-gcc not in PATH"; exit 1; }
|
||||
@command -v bindgen >/dev/null || { echo "bindgen-cli not installed; run: cargo install bindgen-cli"; exit 1; }
|
||||
@mkdir -p $(BUILD)/glue
|
||||
@printf '%s\n' "$$NRFX_CONFIG_H_BODY" > $(BUILD)/glue/nrfx_config.h
|
||||
@printf '%s\n' "$$NRFX_GLUE_H_BODY" > $(BUILD)/glue/nrfx_glue.h
|
||||
@printf '%s\n' "$$NRFX_LOG_H_BODY" > $(BUILD)/glue/nrfx_log.h
|
||||
@printf '%s\n' "$$NRFX_WRAPPER_H_BODY" > $(BUILD)/glue/wrapper.h
|
||||
@echo "── Compiling libnrfx_nfct.a ──────────────────────────────────────────"
|
||||
@for src in nrfx_nfct.c nrfx_timer.c; do \
|
||||
arm-none-eabi-gcc -c -mthumb -mcpu=cortex-m4 -mfloat-abi=soft \
|
||||
-DNRF52840_XXAA -D__HEAP_SIZE=0 -D__STACK_SIZE=0 \
|
||||
-fno-builtin -fno-strict-aliasing \
|
||||
-Wno-unused-parameter -Wno-expansion-to-defined -O2 \
|
||||
$(NRFX_INCLUDES) \
|
||||
-o $(BUILD)/$${src%.c}.o \
|
||||
$(BUILD)/nrfx/drivers/src/$${src} || exit 1; \
|
||||
done
|
||||
@arm-none-eabi-ar rcs $(VENDOR)/lib/libnrfx_nfct.a \
|
||||
$(BUILD)/nrfx_nfct.o $(BUILD)/nrfx_timer.o
|
||||
@echo "── Generating nrfx_nfct_bindings.rs ─────────────────────────────────"
|
||||
@bindgen $(BUILD)/glue/wrapper.h \
|
||||
--use-core --ctypes-prefix cty --no-layout-tests --with-derive-default \
|
||||
--allowlist-function 'nrfx_nfct_.*' --allowlist-function 'nrf_nfct_.*' \
|
||||
--allowlist-type 'nrfx_nfct_.*' --allowlist-type 'nrf_nfct_.*' \
|
||||
--allowlist-var 'NRFX_NFCT_.*' --allowlist-var 'NRF_NFCT_.*' \
|
||||
--output $(VENDOR)/nrfx_nfct_bindings.rs \
|
||||
-- --target=thumbv7em-none-eabi -mthumb -mcpu=cortex-m4 -DNRF52840_XXAA \
|
||||
-isystem "$$(arm-none-eabi-gcc -print-sysroot)/include" \
|
||||
$(NRFX_INCLUDES)
|
||||
|
||||
# ── regen-t4t ───────────────────────────────────────────────────────────────
|
||||
#
|
||||
# Re-generate nfc_t4t_bindings.rs. The .a is Nordic's closed-source
|
||||
# blob — copy a new vendor/lib/libnfc_t4t.a from upstream nrfxlib by
|
||||
# hand before running this if you're bumping the version.
|
||||
regen-t4t:
|
||||
@command -v arm-none-eabi-gcc >/dev/null || { echo "arm-none-eabi-gcc not in PATH"; exit 1; }
|
||||
@command -v bindgen >/dev/null || { echo "bindgen-cli not installed; run: cargo install bindgen-cli"; exit 1; }
|
||||
@mkdir -p $(BUILD)
|
||||
@printf '%s\n' "$$T4T_WRAPPER_H_BODY" > $(BUILD)/t4t_wrapper.h
|
||||
@bindgen $(BUILD)/t4t_wrapper.h \
|
||||
--use-core --ctypes-prefix cty --no-layout-tests --with-derive-default \
|
||||
--allowlist-function 'nfc_t4t_.*' \
|
||||
--allowlist-type 'nfc_t4t_.*' \
|
||||
--allowlist-var 'NFC_T4T_.*' \
|
||||
--output $(VENDOR)/nfc_t4t_bindings.rs \
|
||||
-- --target=thumbv7em-none-eabi -mthumb -mcpu=cortex-m4 -DNRF52840_XXAA \
|
||||
-isystem "$$(arm-none-eabi-gcc -print-sysroot)/include" \
|
||||
-I$(VENDOR)/include
|
||||
|
||||
$(BUILD)/nrfx/.git:
|
||||
@mkdir -p $(BUILD)
|
||||
git clone https://github.com/NordicSemiconductor/nrfx.git $(BUILD)/nrfx
|
||||
cd $(BUILD)/nrfx && git checkout $(NRFX_COMMIT)
|
||||
|
||||
$(BUILD)/cmsis/.git:
|
||||
@mkdir -p $(BUILD)
|
||||
git clone --filter=blob:none https://github.com/ARM-software/CMSIS_6 $(BUILD)/cmsis
|
||||
cd $(BUILD)/cmsis && git checkout $(CMSIS_COMMIT)
|
||||
@@ -0,0 +1,21 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// build.rs — link the vendored static archives. Both .a's plus their
|
||||
// bindgen output live under ./vendor and are committed; this build does
|
||||
// no C compilation and runs no bindgen. Regenerate via `make regen`
|
||||
// when upstream sources change.
|
||||
|
||||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn main() {
|
||||
let manifest = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
let lib_path = manifest.join("vendor/lib");
|
||||
println!("cargo:rustc-link-search=native={}", lib_path.display());
|
||||
println!("cargo:rustc-link-lib=static=nrfx_nfct");
|
||||
println!("cargo:rustc-link-lib=static=nfc_t4t");
|
||||
println!("cargo:rerun-if-changed=vendor/lib/libnrfx_nfct.a");
|
||||
println!("cargo:rerun-if-changed=vendor/lib/libnfc_t4t.a");
|
||||
println!("cargo:rerun-if-changed=vendor/nrfx_nfct_bindings.rs");
|
||||
println!("cargo:rerun-if-changed=vendor/nfc_t4t_bindings.rs");
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
//! `nrf-nfc` — nRF52840 NFC stack.
|
||||
//!
|
||||
//! Two modules, each a thin Rust layer over a vendored static archive:
|
||||
//!
|
||||
//! - [`nrfx_nfct`] — chip-layer driver (Nordic's MIT-licensed nrfx_nfct.c
|
||||
//! pre-compiled as `libnrfx_nfct.a`).
|
||||
//! - [`nfc_t4t`] — ISO 14443-4 Type 4 Tag library (Nordic's closed-source
|
||||
//! `libnfc_t4t.a`) plus the Rust platform-glue the library calls back
|
||||
//! into.
|
||||
//!
|
||||
//! Both .a's and their bindgen outputs live in `vendor/`; see
|
||||
//! `vendor/README.md` for provenance and `Makefile` for `make regen`.
|
||||
|
||||
#![no_std]
|
||||
#![allow(non_camel_case_types, non_snake_case, non_upper_case_globals)]
|
||||
|
||||
pub mod nfc_t4t;
|
||||
pub mod nrfx_nfct;
|
||||
@@ -0,0 +1,223 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
//! Type 4 Tag library — FFI to Nordic's closed-source `libnfc_t4t.a`
|
||||
//! (vendored at `vendor/lib/libnfc_t4t.a`) plus the Rust platform-glue
|
||||
//! the library calls back into.
|
||||
//!
|
||||
//! The public T4T API bindings are pre-generated and committed at
|
||||
//! `vendor/nfc_t4t_bindings.rs`.
|
||||
//!
|
||||
//! `libnfc_t4t.a` links against six C-ABI symbols (per
|
||||
//! `nm vendor/lib/libnfc_t4t.a | grep ' U '`):
|
||||
//!
|
||||
//! nfc_platform_setup
|
||||
//! nfc_platform_nfcid1_default_bytes_get
|
||||
//! nfc_platform_event_handler
|
||||
//! nfc_platform_cb_request
|
||||
//! nfc_platform_buffer_alloc
|
||||
//! nfc_platform_buffer_free
|
||||
//!
|
||||
//! Modeled on Nordic's NCS reference (`nrf/subsys/nfc/lib/platform.c`,
|
||||
//! BSD-3) without the Zephyr clock-control dependency: HFXO is started
|
||||
//! once at boot in the runner and stays on, so we drive ACTIVATE
|
||||
//! synchronously when a field is detected.
|
||||
//!
|
||||
//! The shims run in NFCT IRQ context (priority 4); the library trusts
|
||||
//! pointer validity, and the buffer pool is single-flighted via the
|
||||
//! in-use flag.
|
||||
|
||||
include!("../vendor/nfc_t4t_bindings.rs");
|
||||
|
||||
// Each `pub unsafe extern "C" fn` below is an FFI entry point invoked
|
||||
// solely by libnfc_t4t.a. The safety contract is fixed by the .a's
|
||||
// calling code.
|
||||
#[allow(clippy::missing_safety_doc)]
|
||||
mod platform {
|
||||
use core::ffi::c_void;
|
||||
use core::ptr;
|
||||
use core::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
use crate::nrfx_nfct::{
|
||||
nrfx_nfct_evt_id_t_NRFX_NFCT_EVT_FIELD_DETECTED,
|
||||
nrfx_nfct_evt_id_t_NRFX_NFCT_EVT_FIELD_LOST, nrfx_nfct_evt_t, nrfx_nfct_state_force,
|
||||
nrfx_nfct_state_t_NRFX_NFCT_STATE_ACTIVATED,
|
||||
};
|
||||
|
||||
/// Library callback resolver — libnfc_t4t.a hands us a function pointer
|
||||
/// of this shape during `nfc_platform_setup`; we invoke it from
|
||||
/// `nfc_platform_cb_request`.
|
||||
pub type nfc_lib_cb_resolve_t = unsafe extern "C" fn(p_ctx: *const c_void, p_data: *const u8);
|
||||
|
||||
// ── Per-tag DMA buffer pool (Type 4 Tag) ───────────────────────────────
|
||||
//
|
||||
// `NFC_PLATFORM_T4T_BUFFER_SIZE = 259` from nfc_platform.h — sized to
|
||||
// hold FSD=256 plus a 3-byte WTX frame. We give the library twice that
|
||||
// for its TX+RX areas and single-flight allocations: the library owns
|
||||
// the whole pool or none of it.
|
||||
//
|
||||
// 4-byte alignment for the EasyDMA-backed NFCT engine. The peripheral's
|
||||
// register reference is silent on alignment, but every other EasyDMA
|
||||
// peripheral on this part requires word alignment, so we honor the
|
||||
// stricter constraint.
|
||||
|
||||
const T4T_BUFFER_SIZE: usize = 259;
|
||||
const T4T_TOTAL_BUF: usize = 2 * T4T_BUFFER_SIZE;
|
||||
|
||||
#[repr(align(4))]
|
||||
struct AlignedBuf([u8; T4T_TOTAL_BUF]);
|
||||
|
||||
static mut S_T4T_BUF: AlignedBuf = AlignedBuf([0u8; T4T_TOTAL_BUF]);
|
||||
static S_BUF_IN_USE: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
// Set by `nfc_platform_setup`, read by `nfc_platform_cb_request`.
|
||||
// Single-writer (setup runs once at boot, in thread mode), single-reader
|
||||
// (cb_request runs in IRQ).
|
||||
static mut S_CB_RESOLVE: Option<nfc_lib_cb_resolve_t> = None;
|
||||
|
||||
// ── nfc_platform_setup ─────────────────────────────────────────────────
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn nfc_platform_setup(
|
||||
nfc_lib_cb_resolve: Option<nfc_lib_cb_resolve_t>,
|
||||
p_irq_priority: *mut u8,
|
||||
) -> i32 {
|
||||
if nfc_lib_cb_resolve.is_none() || p_irq_priority.is_null() {
|
||||
return -22; // -EINVAL
|
||||
}
|
||||
S_CB_RESOLVE = nfc_lib_cb_resolve;
|
||||
*p_irq_priority = 6;
|
||||
defmt::info!("nfc_platform: setup OK");
|
||||
0
|
||||
}
|
||||
|
||||
// ── nfc_platform_nfcid1_default_bytes_get ──────────────────────────────
|
||||
//
|
||||
// Derive default NFCID1 bytes from `FICR.DEVICEADDR` (universally
|
||||
// present; FICR.NFC.TAGHEADER doesn't exist on every SoC). Byte 0 =
|
||||
// 0x04 (NXP cascade tag) — without it iPhone classifies the device as
|
||||
// a generic "fake" tag. Length must be 4, 7, or 10 per ISO 14443-3
|
||||
// NFCID1 sizes.
|
||||
|
||||
const FICR_DEVICEADDR0: *const u32 = 0x1000_0060 as *const u32;
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn nfc_platform_nfcid1_default_bytes_get(
|
||||
p_buf: *mut u8,
|
||||
buf_len: u32,
|
||||
) -> i32 {
|
||||
if p_buf.is_null() {
|
||||
return -22; // -EINVAL
|
||||
}
|
||||
if buf_len != 4 && buf_len != 7 && buf_len != 10 {
|
||||
return -7; // -E2BIG
|
||||
}
|
||||
let a = ptr::read_volatile(FICR_DEVICEADDR0);
|
||||
let b = ptr::read_volatile(FICR_DEVICEADDR0.offset(1));
|
||||
|
||||
*p_buf.offset(0) = 0x04;
|
||||
*p_buf.offset(1) = (a >> 24) as u8;
|
||||
*p_buf.offset(2) = (a >> 16) as u8;
|
||||
*p_buf.offset(3) = (a >> 8) as u8;
|
||||
|
||||
if buf_len >= 7 {
|
||||
*p_buf.offset(4) = (b >> 24) as u8;
|
||||
*p_buf.offset(5) = (b >> 16) as u8;
|
||||
*p_buf.offset(6) = (b >> 8) as u8;
|
||||
if buf_len == 10 {
|
||||
*p_buf.offset(7) = b as u8;
|
||||
*p_buf.offset(8) = a as u8;
|
||||
*p_buf.offset(9) = ((a >> 16) ^ (b >> 16)) as u8;
|
||||
}
|
||||
}
|
||||
defmt::info!(
|
||||
"nfc_platform: nfcid_default len={} byte0={=u8:#x}",
|
||||
buf_len,
|
||||
*p_buf
|
||||
);
|
||||
0
|
||||
}
|
||||
|
||||
// ── nfc_platform_event_handler ─────────────────────────────────────────
|
||||
//
|
||||
// libnfc_t4t.a forwards a subset of nrfx events so the platform can
|
||||
// react to field transitions:
|
||||
//
|
||||
// 1. FIELD_DETECTED — drive NFCT to ACTIVATED. The library leaves this
|
||||
// to the platform because the NCS reference gates it on HFXO
|
||||
// becoming ready; our HFXO is permanently on, so we activate
|
||||
// synchronously.
|
||||
//
|
||||
// 2. FIELD_LOST — restore FRAMEDELAYMAX to the spec default. The
|
||||
// library widens it during ISO-DEP; without restoring, the next
|
||||
// session's anti-coll runs in too wide a window and readers reject
|
||||
// the response.
|
||||
|
||||
// FRAMEDELAYMAX register, fixed by the SVD; see nRF52840 product
|
||||
// spec §6.18 (NFCT).
|
||||
const NRF_NFCT_FRAMEDELAYMAX: *mut u32 = 0x4000_5508 as *mut u32;
|
||||
const FRAMEDELAYMAX_SPEC_DEFAULT: u32 = 0x1000;
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn nfc_platform_event_handler(p_event: *const nrfx_nfct_evt_t) {
|
||||
let id = (*p_event).evt_id;
|
||||
if id == nrfx_nfct_evt_id_t_NRFX_NFCT_EVT_FIELD_DETECTED {
|
||||
defmt::info!("nfc_platform: FIELD_DETECTED");
|
||||
nrfx_nfct_state_force(nrfx_nfct_state_t_NRFX_NFCT_STATE_ACTIVATED);
|
||||
} else if id == nrfx_nfct_evt_id_t_NRFX_NFCT_EVT_FIELD_LOST {
|
||||
defmt::info!("nfc_platform: FIELD_LOST (FRAMEDELAYMAX restored)");
|
||||
ptr::write_volatile(NRF_NFCT_FRAMEDELAYMAX, FRAMEDELAYMAX_SPEC_DEFAULT);
|
||||
} else {
|
||||
defmt::info!("nfc_platform: nrfx evt {=u32:#x}", id);
|
||||
}
|
||||
}
|
||||
|
||||
// ── nfc_platform_cb_request ────────────────────────────────────────────
|
||||
//
|
||||
// libnfc_t4t.a uses this to dispatch deferred callbacks. We invoke the
|
||||
// resolver directly (no scheduling), so the library callback runs in
|
||||
// the NFCT IRQ.
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn nfc_platform_cb_request(
|
||||
p_ctx: *const c_void,
|
||||
_ctx_len: usize,
|
||||
p_data: *const u8,
|
||||
_data_len: usize,
|
||||
_copy_data: bool,
|
||||
) {
|
||||
defmt::info!(
|
||||
"nfc_platform: cb_request ctx={=u32:#x} data={=u32:#x}",
|
||||
p_ctx as u32,
|
||||
p_data as u32
|
||||
);
|
||||
if let Some(resolve) = S_CB_RESOLVE {
|
||||
resolve(p_ctx, p_data);
|
||||
}
|
||||
}
|
||||
|
||||
// ── nfc_platform_buffer_alloc / free ───────────────────────────────────
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn nfc_platform_buffer_alloc(size: usize) -> *mut u8 {
|
||||
let in_use = S_BUF_IN_USE.load(Ordering::SeqCst);
|
||||
defmt::info!(
|
||||
"nfc_platform: buf_alloc size={=usize} in_use={=bool}",
|
||||
size,
|
||||
in_use
|
||||
);
|
||||
if in_use || size > T4T_TOTAL_BUF {
|
||||
return ptr::null_mut();
|
||||
}
|
||||
S_BUF_IN_USE.store(true, Ordering::SeqCst);
|
||||
core::ptr::addr_of_mut!(S_T4T_BUF.0) as *mut u8
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn nfc_platform_buffer_free(p_buf: *mut u8) {
|
||||
defmt::info!("nfc_platform: buf_free p={=u32:#x}", p_buf as u32);
|
||||
let our_buf = core::ptr::addr_of_mut!(S_T4T_BUF.0) as *mut u8;
|
||||
if p_buf == our_buf {
|
||||
S_BUF_IN_USE.store(false, Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
//! Chip-layer driver — FFI to Nordic's MIT-licensed `nrfx_nfct.c`,
|
||||
//! pre-compiled into `vendor/lib/libnrfx_nfct.a`.
|
||||
//!
|
||||
//! The bindgen output is committed at `vendor/nrfx_nfct_bindings.rs`;
|
||||
//! this module just `include!`s it and adds two C-ABI helpers the
|
||||
//! driver needs at runtime (critical-section + microsecond delay).
|
||||
//!
|
||||
//! IRQ handlers `nrfx_nfct_irq_handler` and
|
||||
//! `nrfx_nfct_workaround_timer_handler` are exported by the .a; the
|
||||
//! runner's RTIC `binds = NFCT` / `binds = TIMER4` tasks call them.
|
||||
|
||||
// Pre-generated by bindgen — see vendor/README.md and the regen target.
|
||||
include!("../vendor/nrfx_nfct_bindings.rs");
|
||||
|
||||
// ── Critical section ─────────────────────────────────────────────────────
|
||||
//
|
||||
// nrfx's critical-section convention: enter() returns a state that exit()
|
||||
// restores. We mirror PRIMASK behavior so nested critical sections nest
|
||||
// correctly: enter() saves the current PRIMASK and disables interrupts;
|
||||
// exit() writes the saved value back.
|
||||
//
|
||||
// We avoid `cortex_m::interrupt::free` because that closure-based API
|
||||
// doesn't compose with the C macro pattern (enter/exit on different lines).
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn nrfx_critical_section_enter() -> u8 {
|
||||
let primask = cortex_m::register::primask::read();
|
||||
cortex_m::interrupt::disable();
|
||||
if primask.is_active() {
|
||||
0
|
||||
} else {
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn nrfx_critical_section_exit(saved: u8) {
|
||||
if saved == 0 {
|
||||
// PRIMASK was clear (interrupts enabled) before enter() — re-enable.
|
||||
unsafe { cortex_m::interrupt::enable() };
|
||||
}
|
||||
}
|
||||
|
||||
// ── Microsecond delay (busy loop, calibrated for 64 MHz core) ────────────
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn nrfx_delay_us(us: u32) {
|
||||
// cortex_m::asm::delay takes cycles; at 64 MHz, 64 cycles = 1 µs.
|
||||
cortex_m::asm::delay(us.saturating_mul(64));
|
||||
}
|
||||
Vendored
+30
@@ -0,0 +1,30 @@
|
||||
Copyright (c) 2017 - 2026, Nordic Semiconductor ASA
|
||||
All rights reserved.
|
||||
|
||||
SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from this
|
||||
software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
Vendored
+44
@@ -0,0 +1,44 @@
|
||||
# Vendored NFC artifacts
|
||||
|
||||
Pre-built artifacts the `nrf-nfc` crate links against. Both `.a`'s and
|
||||
their bindgen outputs are committed so the normal build needs no nrfx
|
||||
clone, no CMSIS clone, and no C cross-compiler.
|
||||
|
||||
## libnrfx_nfct.a (chip layer)
|
||||
|
||||
Compiled from Nordic's MIT-licensed
|
||||
[nrfx](https://github.com/NordicSemiconductor/nrfx) NFCT + TIMER
|
||||
drivers. Source commits and build flags are pinned in `../Makefile`.
|
||||
|
||||
| File | Description |
|
||||
|---|---|
|
||||
| `lib/libnrfx_nfct.a` | nrfx_nfct.c + nrfx_timer.c, compiled for thumbv7em-none-eabihf at -O2 |
|
||||
| `nrfx_nfct_bindings.rs` | bindgen output for nrfx_nfct.h + nrf_nfct.h |
|
||||
|
||||
## libnfc_t4t.a (Type 4 Tag library)
|
||||
|
||||
Verbatim copy of Nordic's closed-source Type-4-Tag library (ISO 14443-4
|
||||
ISO-DEP — anti-collision, RATS/ATS, I-block chaining, WTX) from
|
||||
[nrfconnect/sdk-nrfxlib](https://github.com/nrfconnect/sdk-nrfxlib) at
|
||||
commit `529012899ffb2aa8ef69cbbb315eaf2848737aca`.
|
||||
|
||||
| File | Source path in nrfxlib |
|
||||
|---|---|
|
||||
| `lib/libnfc_t4t.a` | `nfc/lib/cortex-m4/hard-float/libnfc_t4t.a` |
|
||||
| `include/nfc_t4t_lib.h` | `nfc/include/nfc_t4t_lib.h` |
|
||||
| `include/nrf_nfc_errno.h` | `nfc/include/nrf_nfc_errno.h` |
|
||||
| `LICENSE` | top-level `LICENSE` (Nordic 5-Clause) |
|
||||
| `nfc_t4t_bindings.rs` | bindgen output for nfc_t4t_lib.h |
|
||||
|
||||
The library's `nfc_platform.h` C-callback contract is implemented in
|
||||
Rust at [`../src/nfc_t4t/nfc_platform.rs`](../src/nfc_t4t/nfc_platform.rs);
|
||||
the header itself is not vendored.
|
||||
|
||||
`include/` is only consumed at regen time (by bindgen-cli), not by
|
||||
the normal build.
|
||||
|
||||
## Regenerating
|
||||
|
||||
When bumping upstream versions, from this crate's directory run
|
||||
`make regen` (requires `arm-none-eabi-gcc` and `bindgen-cli`). The
|
||||
artifacts under this directory get rewritten in place; commit them.
|
||||
+394
@@ -0,0 +1,394 @@
|
||||
/**
|
||||
* Copyright (c) 2016, Telit Communications Cyprus Ltd
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, must reproduce the above copyright notice, this list of
|
||||
* conditions and the following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef NFC_T4T_LIB_H__
|
||||
#define NFC_T4T_LIB_H__
|
||||
|
||||
/** @file nfc_t4t_lib.h
|
||||
*
|
||||
*
|
||||
* @defgroup nfc_t4t NFC Type 4 Tag
|
||||
* @brief Implementation of NFC Type 4 Tag.
|
||||
*
|
||||
* @defgroup nfc_t4t_lib NFC tag 4 type emulation library
|
||||
* @{
|
||||
* @ingroup nfc_t4t
|
||||
* @brief The T4T emulation library interface
|
||||
*
|
||||
* This is the NFC Forum NDEF tag 4 type emulation library. It implements the
|
||||
* ISO14443-4A protocol (ISO-DEP) and additionally can emulate a read-writable
|
||||
* NDEF content. If the emulation of the NDEF content is not needed, the library
|
||||
* works in a raw mode where all APDUs are delivered to the user, who is then
|
||||
* responsible to generate a timely RPDU as a response.
|
||||
*
|
||||
* The sequence of initializing functions determines whether the NDEF emulation
|
||||
* will run or whether the raw mode is used.
|
||||
*
|
||||
* - E.g. NDEF emulation
|
||||
* * @ref nfc_t4t_setup
|
||||
* * @ref nfc_t4t_ndef_rwpayload_set or
|
||||
@ref nfc_t4t_ndef_staticpayload_set
|
||||
* * @ref nfc_t4t_emulation_start
|
||||
* * ... running in NDEF emulation mode
|
||||
* - E.g. RAW mode
|
||||
* * @ref nfc_t4t_setup
|
||||
* * @ref nfc_t4t_emulation_start
|
||||
* * ... running in RAW emulation mode
|
||||
*
|
||||
* @note If you are using nRF52832 chip (in IC rev. Engineering B or
|
||||
* Engineering C) or if You are using nRF52840 chip (in IC rev. Engineering A,
|
||||
* B or C) library will use TIMER 4 to apply workarounds for the anomalies.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define NFC_T4T_MAX_PAYLOAD_SIZE 0xFFF0U
|
||||
|
||||
/**< @brief Emulation mode. */
|
||||
typedef enum
|
||||
{
|
||||
NFC_T4T_EMUMODE_NDEF, /**< Emulated NDEF AID and EF-Files. */
|
||||
NFC_T4T_EMUMODE_PICC /**< Run just ISO-DEP, deliver I-Frames up. */
|
||||
} nfc_t4t_emu_mode_t;
|
||||
|
||||
/**< @brief Event identifiers used by the @ref nfc_t4t_callback_t */
|
||||
typedef enum
|
||||
{
|
||||
NFC_T4T_EVENT_NONE,
|
||||
/**< This ID is never used. Dummy value for completeness. */
|
||||
|
||||
NFC_T4T_EVENT_FIELD_ON,
|
||||
/**< External Reader polling detected. */
|
||||
|
||||
NFC_T4T_EVENT_FIELD_OFF,
|
||||
/**< External Reader polling ended. */
|
||||
|
||||
NFC_T4T_EVENT_NDEF_READ,
|
||||
/**< External Reader has read static NDEF-Data from Emulation. */
|
||||
/**<
|
||||
* A Read operation happened on last byte of NDEF-Data.
|
||||
*/
|
||||
|
||||
NFC_T4T_EVENT_NDEF_UPDATED,
|
||||
/**< External Reader has written to length information of NDEF-Data from
|
||||
* Emulation.
|
||||
*/
|
||||
/**<
|
||||
* The usual behavior of a Reader-Writer that accesses NDEF information
|
||||
* for update is to set the length to zero at the beginning of the
|
||||
* update process. It then writes the content of NDEF-Data. When all
|
||||
* content is written it will update the length information inside the
|
||||
* NDEF file. This event will be generated every time an update to the
|
||||
* length is happening. This length information is residing in the first
|
||||
* 2 bytes of the NDEF-Content container and is called 'NLEN'. Since
|
||||
* this callback is triggered on any access to these bytes the returned
|
||||
* data_length information might not be consistent (e.g. in case of only
|
||||
* a single byte write to the length).
|
||||
*
|
||||
* @param data Pointer to current data of NDEF message
|
||||
* @param data_length Current value of NDEF content length information
|
||||
* i.e. 'NLEN' field.
|
||||
*/
|
||||
|
||||
NFC_T4T_EVENT_DATA_TRANSMITTED,
|
||||
/**< In Raw mode it signals that the data from @ref
|
||||
* nfc_t4t_response_pdu_send have been sent out.
|
||||
*/
|
||||
|
||||
NFC_T4T_EVENT_DATA_IND,
|
||||
/**< In Raw mode delivers the APDU fragments */
|
||||
/**<
|
||||
* All @ref NFC_T4T_EVENT_DATA_IND events that have the @ref
|
||||
* NFC_T4T_DI_FLAG_MORE flag set belong to the same APDU. The first
|
||||
* @ref NFC_T4T_EVENT_DATA_IND without @ref NFC_T4T_DI_FLAG_MORE
|
||||
* flag signals the completeness of the APDU. The Application then has
|
||||
* to reply with a call to @ref nfc_t4t_response_pdu_send. The library
|
||||
* will handle internally the fragmentation of the response towards the
|
||||
* Reader-Writer. The data of the response PDU must be kept valid until
|
||||
* the next callback from the library happens (e.g. next @ref
|
||||
* NFC_T4T_EVENT_DATA_IND or @ref NFC_T4T_EVENT_FIELD_OFF).
|
||||
*
|
||||
* @param data Pointer to the fragment of APDU.
|
||||
* @param data_length Length of data.
|
||||
* @param flags nfc_t4t_data_ind_flags.
|
||||
*/
|
||||
} nfc_t4t_event_t;
|
||||
|
||||
/**< @brief Flags coming with nfc_t4t_callback_t at @ref
|
||||
* NFC_T4T_EVENT_DATA_IND event.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
NFC_T4T_DI_FLAG_NONE = 0x00, /**< Dummy value. */
|
||||
NFC_T4T_DI_FLAG_MORE = 0x01
|
||||
/**< This signals that more data is expected to be received. */
|
||||
} nfc_t4t_data_ind_flags_t;
|
||||
|
||||
/**< @brief Maximum values for the Frame Wait time Integer. */
|
||||
typedef enum
|
||||
{
|
||||
NFC_T4T_FWI_MAX_VAL_EMV = 0x07, /**< Value specified by the EMV specification. */
|
||||
NFC_T4T_FWI_MAX_VAL_NFC = 0x08 /**< Value specified by the NFC specification. */
|
||||
} nfc_t4t_fwi_max_val_t;
|
||||
|
||||
/**< @brief Parameter IDs that can be set/get with @ref nfc_t4t_parameter_set or
|
||||
* @ref nfc_t4t_parameter_get.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
NFC_T4T_PARAM_FWI,
|
||||
/**< Frame Wait Time parameter.
|
||||
* The maximum allowed value is limited by the NFC_T4T_PARAM_FWI_MAX parameter.
|
||||
* In case of nRF52832 the maximum allowed value is 4,
|
||||
* setting the parameter higher will result in silent truncation to 4.
|
||||
*/
|
||||
|
||||
NFC_T4T_PARAM_FDT_MIN,
|
||||
/**< Frame Delay Time Min parameter
|
||||
* The parameter controls the frame transmission timing during collision resolution.
|
||||
*/
|
||||
|
||||
NFC_T4T_PARAM_SELRES,
|
||||
/**< Parameter for setting 'Protocol' bits for SEL_RES packet */
|
||||
|
||||
NFC_T4T_PARAM_NFCID1,
|
||||
/**< NFCID1 value, data can be 4, 7, or 10 bytes long (single, double,
|
||||
* or triple size). To use default NFCID1 of specific length pass one
|
||||
* byte containing requested length. Default 7-byte NFCID1 will be
|
||||
* used if this parameter was not set. This parameter can be set
|
||||
* before nfc_t2t_setup() to set initial NFCID1 and it can be changed
|
||||
* later.
|
||||
*/
|
||||
|
||||
NFC_T4T_PARAM_FWI_MAX,
|
||||
/**< Maximum value for the Frame Wait time Integer.
|
||||
* Valid parameter values are 7 and 8.
|
||||
* The default value is 8.
|
||||
* This parameter can be used to limit the maximum FWI value to 7,
|
||||
* to align the implementation with the EMV specifications.
|
||||
*/
|
||||
} nfc_t4t_param_id_t;
|
||||
|
||||
/** @brief Callback to pass events from NFCLib to application.
|
||||
*
|
||||
* @param context Application context for callback execution.
|
||||
* @param event The event that occurred. see nfc_t4t_event.
|
||||
* @param data Data to send to the application (event specific).
|
||||
* @param data_length Length of the data. In case of @ref
|
||||
* NFC_T4T_EVENT_NDEF_UPDATED, this parameter contains the value of the 'NLEN'
|
||||
* field of the NDEF File; if the value is non-zero, it corresponds to the new
|
||||
* size of the NDEF Message in the updated NDEF File.
|
||||
* @param flags Some events deliver flags. see nfc_t4t_event for details.
|
||||
*/
|
||||
typedef void (*nfc_t4t_callback_t)(void *context,
|
||||
nfc_t4t_event_t event,
|
||||
const uint8_t *data,
|
||||
size_t data_length,
|
||||
uint32_t flags);
|
||||
|
||||
/** @brief Register the application callback for event signaling.
|
||||
*
|
||||
* The callback will be called by NFCLib to notify the application of relevant
|
||||
* events. It will be called from the HAL_NFC callback context. The library
|
||||
* support 3 different Modes of Emulation:
|
||||
* - Raw ISO-Dep exchanges. All PDUs are signaled through the callback.
|
||||
* - Read-Only T4T NDEF-Tag. A static buffer is served. Only Field-Status
|
||||
* callbacks.
|
||||
* - Read-Write T4T NDEF-Tag. A mutable buffer is used. Only Field-Status
|
||||
* callbacks.
|
||||
*
|
||||
* The default mode is Raw ISO-Dep mode. The two other NDEF T4T modes are
|
||||
* activated through the corresponding @ref nfc_t4t_ndef_rwpayload_set/ @ref
|
||||
* nfc_t4t_ndef_staticpayload_set functions. The mode is locked in with a call
|
||||
* to @ref nfc_t4t_emulation_start.
|
||||
*
|
||||
* @param callback Function pointer to the callback.
|
||||
* @param context Pointer to a memory area used by the callback for execution
|
||||
* (optional).
|
||||
*
|
||||
* @retval 0 Success.
|
||||
* @retval -NRF_EINVAL Invalid argument (e.g. wrong data length, NULL pointer))
|
||||
* @retval -NRF_EOPNOTSUPP If emulation is in running state.
|
||||
*/
|
||||
int nfc_t4t_setup(nfc_t4t_callback_t callback, void *context);
|
||||
|
||||
/** @brief Set emulation buffer and content for a NDEF Tag emulation that is
|
||||
* Read/Writable.
|
||||
*
|
||||
* The buffer needs to be kept accessible for the lifetime of the emulation.
|
||||
* If an external Reader-Writer changes the NDEF content it is signaled through
|
||||
* the app-callback. Buffer can be changed during the lifetime of the emulation,
|
||||
* when NDEF READ or UPDATE procedure is pending, and it will be changed after
|
||||
* this procedure has completed. To perform this procedure safely, make sure to
|
||||
* disable NFC interrupts.
|
||||
*
|
||||
* @param emulation_buffer Buffer pointer
|
||||
* @param buffer_length Length of buffer (maximum writable NDEF size)
|
||||
*
|
||||
* @retval 0 Success.
|
||||
* @retval -NRF_EINVAL Invalid argument (for example, wrong data length, NULL pointer).
|
||||
* @retval -NRF_EOPNOTSUPP If the new buffer has a different length than the first one.
|
||||
* @retval -NRF_EFAULT If the provided buffer is the currently used buffer.
|
||||
*/
|
||||
int nfc_t4t_ndef_rwpayload_set(uint8_t *emulation_buffer,
|
||||
size_t buffer_length);
|
||||
|
||||
/** @brief Set emulation buffer and content for an NDEF Tag emulation that is
|
||||
* Read-Only.
|
||||
*
|
||||
* The buffer needs to be kept accessible for the lifetime of the emulation.
|
||||
* Since no write access is done to the buffer, the content could reside in
|
||||
* flash memory.
|
||||
*
|
||||
* @param emulation_buffer Const buffer pointer
|
||||
* @param buffer_length Length of contained NDEF payload message
|
||||
*
|
||||
* @retval 0 Success.
|
||||
* @retval -NRF_EINVAL Invalid argument (for example, wrong data length, NULL pointer).
|
||||
* @retval -NRF_EOPNOTSUPP Emulation is in running stated.
|
||||
*/
|
||||
int nfc_t4t_ndef_staticpayload_set(const uint8_t *emulation_buffer,
|
||||
size_t buffer_length);
|
||||
|
||||
/** @brief Send a raw response PDU after getting a Request PDU callback.
|
||||
*
|
||||
* When the library works in raw ISO-DEP mode it will signal request PDUs
|
||||
* through the callback. The application then has to answer with a response PDU.
|
||||
* It will use this function to send back the response PDU. This function can
|
||||
* not be used in T4T NDEF (RW / STATIC) emulation modes.
|
||||
*
|
||||
* The lower ISODEP layer will handle the defragmentation of a long response PDU
|
||||
* into smalleR pieces that the PCD can understand.
|
||||
*
|
||||
* @param pdu Const PDU pointer.
|
||||
* @param pdu_length Length of PDU.
|
||||
*
|
||||
* @retval 0 Success.
|
||||
* @retval -NRF_EINVAL Invalid argument (for example, wrong data length, NULL pointer).
|
||||
* @retval -NRF_EOPNOTSUPP Emulation is in running state.
|
||||
*/
|
||||
int nfc_t4t_response_pdu_send(const uint8_t *pdu, size_t pdu_length);
|
||||
|
||||
/** @brief Set an NFC parameter.
|
||||
*
|
||||
* Allows to set an NFC configuration parameter.
|
||||
*
|
||||
* @param id ID of the parameter to set.
|
||||
* @param data Pointer to a buffer containing the data to set.
|
||||
* @param data_length Size of the buffer containing the data to set.
|
||||
*
|
||||
* @retval 0 Success.
|
||||
* @retval -NRF_EINVAL Invalid argument (for example, wrong data length, NULL pointer).
|
||||
*/
|
||||
int nfc_t4t_parameter_set(nfc_t4t_param_id_t id,
|
||||
void *data,
|
||||
size_t data_length);
|
||||
|
||||
/** @brief Query an NFC parameter value.
|
||||
*
|
||||
* The queried value will be placed into the passed data buffer.
|
||||
* If the buffer is too small, max_data_length will contain the required
|
||||
* buffer size. If the buffer is big enough, max_data_length will contain
|
||||
* the actual size of the data.
|
||||
*
|
||||
* @param id ID of the parameter to query.
|
||||
* @param data Pointer to a buffer receiving the queried data.
|
||||
* @param max_data_length Size of the buffer, receives actual size of queried
|
||||
* data.
|
||||
*
|
||||
* @retval 0 Success.
|
||||
* @retval -NRF_EINVAL Invalid argument (for example, wrong data length, NULL pointer).
|
||||
*/
|
||||
int nfc_t4t_parameter_get(nfc_t4t_param_id_t id,
|
||||
void *data,
|
||||
size_t *max_data_length);
|
||||
|
||||
/** @brief Activate the NFC frontend.
|
||||
*
|
||||
* Only after calling this function, events will be posted to the application
|
||||
* callback.
|
||||
*
|
||||
* @retval 0 Success.
|
||||
* @retval -NRF_EOPNOTSUPP Already started.
|
||||
*/
|
||||
int nfc_t4t_emulation_start(void);
|
||||
|
||||
/**
|
||||
* @brief Deactivate the NFC frontend.
|
||||
*
|
||||
* After calling this function, no more events will be posted to the application
|
||||
* callback.
|
||||
*
|
||||
* @retval 0 Success.
|
||||
* @retval -NRF_EOPNOTSUPP Emulation was already stopped.
|
||||
*/
|
||||
int nfc_t4t_emulation_stop(void);
|
||||
|
||||
/**
|
||||
* @brief Release reference to application callback.
|
||||
*
|
||||
* After calling this function, the passed callback pointer is no longer
|
||||
* considered valid.
|
||||
* After calling this function, the passed ndef pointer is no longer
|
||||
* considered valid.
|
||||
*
|
||||
* You need to restart with @ref nfc_t4t_setup to run a new Emulation.
|
||||
*
|
||||
* @retval 0 Success.
|
||||
* @retval -NRF_EOPNOTSUPP The NFC T4T has been de-initialized already.
|
||||
*/
|
||||
int nfc_t4t_done(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /** NFC_T4T_LIB_H__ */
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
*/
|
||||
|
||||
#ifndef NRF_NFC_ERRNO_H__
|
||||
#define NRF_NFC_ERRNO_H__
|
||||
|
||||
/**
|
||||
* @defgroup nrf_nfc_errno Error codes for nRF NFC libraries.
|
||||
* @{
|
||||
*
|
||||
* @brief Defines error codes that can be used in nRF NFC libraries.
|
||||
*/
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define NRF_EPERM 1 /**< Operation not permitted */
|
||||
#define NRF_ENOENT 2 /**< No such file or directory */
|
||||
#define NRF_EIO 5 /**< Input/output error */
|
||||
#define NRF_ENOEXEC 8 /**< Exec format error */
|
||||
#define NRF_EBADF 9 /**< Bad file descriptor */
|
||||
#define NRF_ENOMEM 12 /**< Cannot allocate memory */
|
||||
#define NRF_EACCES 13 /**< Permission denied */
|
||||
#define NRF_EFAULT 14 /**< Bad address */
|
||||
#define NRF_ENODEV 19 /**< No such device */
|
||||
#define NRF_EINVAL 22 /**< Invalid argument */
|
||||
#define NRF_EMFILE 24 /**< Too many open files */
|
||||
#define NRF_ENOSPC 28 /**< No space left on device */
|
||||
#define NRF_EAGAIN 35 /**< Resource temporarily unavailable*/
|
||||
#define NRF_EDOM 37 /**< Domain error */
|
||||
#define NRF_EMSGSIZE 40 /**< Message too long */
|
||||
#define NRF_EPROTOTYPE 41 /**< Protocol wrong type for socket */
|
||||
#define NRF_ENOPROTOOPT 42 /**< Protocol not available */
|
||||
#define NRF_EPROTONOSUPPORT 43 /**< Protocol not supported */
|
||||
#define NRF_ESOCKTNOSUPPORT 44 /**< Socket type not supported */
|
||||
#define NRF_EOPNOTSUPP 45 /**< Operation not supported */
|
||||
#define NRF_EAFNOSUPPORT 47 /**< Address family not supported by protocol */
|
||||
#define NRF_EADDRINUSE 48 /**< Address already in use */
|
||||
#define NRF_ENETDOWN 50 /**< Network is down */
|
||||
#define NRF_ENETUNREACH 51 /**< Network is unreachable */
|
||||
#define NRF_ENETRESET 52 /**< Connection aborted by network */
|
||||
#define NRF_ECONNRESET 54 /**< Connection reset by peer */
|
||||
#define NRF_EISCONN 56 /**< Transport endpoint is already connected */
|
||||
#define NRF_ENOTCONN 57 /**< Transport endpoint is not connected */
|
||||
#define NRF_ETIMEDOUT 60 /**< Connection timed out */
|
||||
#define NRF_EBADMSG 77 /**< Bad message */
|
||||
#define NRF_ENOBUFS 105 /**< No buffer space available */
|
||||
|
||||
#define NRF_EHOSTDOWN 112 /**< Host is down */
|
||||
#define NRF_EALREADY 114 /**< Operation already in progress */
|
||||
#define NRF_EINPROGRESS 115 /**< Operation in progress */
|
||||
#define NRF_ECANCELED 125 /**< Operation canceled */
|
||||
|
||||
#define NRF_ENOKEY 126 /**< Required key not available */
|
||||
#define NRF_EKEYEXPIRED 127 /**< Key has expired */
|
||||
#define NRF_EKEYREVOKED 128 /**< Key has been revoked */
|
||||
#define NRF_EKEYREJECTED 129 /**< Key was rejected by service */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
@}
|
||||
*/
|
||||
|
||||
#endif // NRF_NFC_ERRNO_H__
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
+91
@@ -0,0 +1,91 @@
|
||||
/* automatically generated by rust-bindgen 0.72.1 */
|
||||
|
||||
pub const NFC_T4T_MAX_PAYLOAD_SIZE: u32 = 65520;
|
||||
#[doc = "< Emulated NDEF AID and EF-Files."]
|
||||
pub const nfc_t4t_emu_mode_t_NFC_T4T_EMUMODE_NDEF: nfc_t4t_emu_mode_t = 0;
|
||||
#[doc = "< Run just ISO-DEP, deliver I-Frames up."]
|
||||
pub const nfc_t4t_emu_mode_t_NFC_T4T_EMUMODE_PICC: nfc_t4t_emu_mode_t = 1;
|
||||
pub type nfc_t4t_emu_mode_t = cty::c_uint;
|
||||
pub const nfc_t4t_event_t_NFC_T4T_EVENT_NONE: nfc_t4t_event_t = 0;
|
||||
pub const nfc_t4t_event_t_NFC_T4T_EVENT_FIELD_ON: nfc_t4t_event_t = 1;
|
||||
pub const nfc_t4t_event_t_NFC_T4T_EVENT_FIELD_OFF: nfc_t4t_event_t = 2;
|
||||
pub const nfc_t4t_event_t_NFC_T4T_EVENT_NDEF_READ: nfc_t4t_event_t = 3;
|
||||
pub const nfc_t4t_event_t_NFC_T4T_EVENT_NDEF_UPDATED: nfc_t4t_event_t = 4;
|
||||
pub const nfc_t4t_event_t_NFC_T4T_EVENT_DATA_TRANSMITTED: nfc_t4t_event_t = 5;
|
||||
pub const nfc_t4t_event_t_NFC_T4T_EVENT_DATA_IND: nfc_t4t_event_t = 6;
|
||||
pub type nfc_t4t_event_t = cty::c_uint;
|
||||
#[doc = "< Dummy value."]
|
||||
pub const nfc_t4t_data_ind_flags_t_NFC_T4T_DI_FLAG_NONE: nfc_t4t_data_ind_flags_t = 0;
|
||||
pub const nfc_t4t_data_ind_flags_t_NFC_T4T_DI_FLAG_MORE: nfc_t4t_data_ind_flags_t = 1;
|
||||
pub type nfc_t4t_data_ind_flags_t = cty::c_uint;
|
||||
#[doc = "< Value specified by the EMV specification."]
|
||||
pub const nfc_t4t_fwi_max_val_t_NFC_T4T_FWI_MAX_VAL_EMV: nfc_t4t_fwi_max_val_t = 7;
|
||||
#[doc = "< Value specified by the NFC specification."]
|
||||
pub const nfc_t4t_fwi_max_val_t_NFC_T4T_FWI_MAX_VAL_NFC: nfc_t4t_fwi_max_val_t = 8;
|
||||
pub type nfc_t4t_fwi_max_val_t = cty::c_uint;
|
||||
pub const nfc_t4t_param_id_t_NFC_T4T_PARAM_FWI: nfc_t4t_param_id_t = 0;
|
||||
pub const nfc_t4t_param_id_t_NFC_T4T_PARAM_FDT_MIN: nfc_t4t_param_id_t = 1;
|
||||
pub const nfc_t4t_param_id_t_NFC_T4T_PARAM_SELRES: nfc_t4t_param_id_t = 2;
|
||||
pub const nfc_t4t_param_id_t_NFC_T4T_PARAM_NFCID1: nfc_t4t_param_id_t = 3;
|
||||
pub const nfc_t4t_param_id_t_NFC_T4T_PARAM_FWI_MAX: nfc_t4t_param_id_t = 4;
|
||||
pub type nfc_t4t_param_id_t = cty::c_uint;
|
||||
#[doc = " @brief Callback to pass events from NFCLib to application.\n\n @param context Application context for callback execution.\n @param event The event that occurred. see nfc_t4t_event.\n @param data Data to send to the application (event specific).\n @param data_length Length of the data. In case of @ref\n NFC_T4T_EVENT_NDEF_UPDATED, this parameter contains the value of the 'NLEN'\n field of the NDEF File; if the value is non-zero, it corresponds to the new\n size of the NDEF Message in the updated NDEF File.\n @param flags Some events deliver flags. see nfc_t4t_event for details."]
|
||||
pub type nfc_t4t_callback_t = ::core::option::Option<
|
||||
unsafe extern "C" fn(
|
||||
context: *mut cty::c_void,
|
||||
event: nfc_t4t_event_t,
|
||||
data: *const u8,
|
||||
data_length: usize,
|
||||
flags: u32,
|
||||
),
|
||||
>;
|
||||
unsafe extern "C" {
|
||||
#[doc = " @brief Register the application callback for event signaling.\n\n The callback will be called by NFCLib to notify the application of relevant\n events. It will be called from the HAL_NFC callback context. The library\n support 3 different Modes of Emulation:\n - Raw ISO-Dep exchanges. All PDUs are signaled through the callback.\n - Read-Only T4T NDEF-Tag. A static buffer is served. Only Field-Status\n callbacks.\n - Read-Write T4T NDEF-Tag. A mutable buffer is used. Only Field-Status\n callbacks.\n\n The default mode is Raw ISO-Dep mode. The two other NDEF T4T modes are\n activated through the corresponding @ref nfc_t4t_ndef_rwpayload_set/ @ref\n nfc_t4t_ndef_staticpayload_set functions. The mode is locked in with a call\n to @ref nfc_t4t_emulation_start.\n\n @param callback Function pointer to the callback.\n @param context Pointer to a memory area used by the callback for execution\n (optional).\n\n @retval 0 Success.\n @retval -NRF_EINVAL Invalid argument (e.g. wrong data length, NULL pointer))\n @retval -NRF_EOPNOTSUPP If emulation is in running state."]
|
||||
pub fn nfc_t4t_setup(callback: nfc_t4t_callback_t, context: *mut cty::c_void) -> cty::c_int;
|
||||
}
|
||||
unsafe extern "C" {
|
||||
#[doc = " @brief Set emulation buffer and content for a NDEF Tag emulation that is\n Read/Writable.\n\n The buffer needs to be kept accessible for the lifetime of the emulation.\n If an external Reader-Writer changes the NDEF content it is signaled through\n the app-callback. Buffer can be changed during the lifetime of the emulation,\n when NDEF READ or UPDATE procedure is pending, and it will be changed after\n this procedure has completed. To perform this procedure safely, make sure to\n disable NFC interrupts.\n\n @param emulation_buffer Buffer pointer\n @param buffer_length Length of buffer (maximum writable NDEF size)\n\n @retval 0 Success.\n @retval -NRF_EINVAL Invalid argument (for example, wrong data length, NULL pointer).\n @retval -NRF_EOPNOTSUPP If the new buffer has a different length than the first one.\n @retval -NRF_EFAULT If the provided buffer is the currently used buffer."]
|
||||
pub fn nfc_t4t_ndef_rwpayload_set(
|
||||
emulation_buffer: *mut u8,
|
||||
buffer_length: usize,
|
||||
) -> cty::c_int;
|
||||
}
|
||||
unsafe extern "C" {
|
||||
#[doc = " @brief Set emulation buffer and content for an NDEF Tag emulation that is\n Read-Only.\n\n The buffer needs to be kept accessible for the lifetime of the emulation.\n Since no write access is done to the buffer, the content could reside in\n flash memory.\n\n @param emulation_buffer Const buffer pointer\n @param buffer_length Length of contained NDEF payload message\n\n @retval 0 Success.\n @retval -NRF_EINVAL Invalid argument (for example, wrong data length, NULL pointer).\n @retval -NRF_EOPNOTSUPP Emulation is in running stated."]
|
||||
pub fn nfc_t4t_ndef_staticpayload_set(
|
||||
emulation_buffer: *const u8,
|
||||
buffer_length: usize,
|
||||
) -> cty::c_int;
|
||||
}
|
||||
unsafe extern "C" {
|
||||
#[doc = " @brief Send a raw response PDU after getting a Request PDU callback.\n\n When the library works in raw ISO-DEP mode it will signal request PDUs\n through the callback. The application then has to answer with a response PDU.\n It will use this function to send back the response PDU. This function can\n not be used in T4T NDEF (RW / STATIC) emulation modes.\n\n The lower ISODEP layer will handle the defragmentation of a long response PDU\n into smalleR pieces that the PCD can understand.\n\n @param pdu Const PDU pointer.\n @param pdu_length Length of PDU.\n\n @retval 0 Success.\n @retval -NRF_EINVAL Invalid argument (for example, wrong data length, NULL pointer).\n @retval -NRF_EOPNOTSUPP Emulation is in running state."]
|
||||
pub fn nfc_t4t_response_pdu_send(pdu: *const u8, pdu_length: usize) -> cty::c_int;
|
||||
}
|
||||
unsafe extern "C" {
|
||||
#[doc = " @brief Set an NFC parameter.\n\n Allows to set an NFC configuration parameter.\n\n @param id ID of the parameter to set.\n @param data Pointer to a buffer containing the data to set.\n @param data_length Size of the buffer containing the data to set.\n\n @retval 0 Success.\n @retval -NRF_EINVAL Invalid argument (for example, wrong data length, NULL pointer)."]
|
||||
pub fn nfc_t4t_parameter_set(
|
||||
id: nfc_t4t_param_id_t,
|
||||
data: *mut cty::c_void,
|
||||
data_length: usize,
|
||||
) -> cty::c_int;
|
||||
}
|
||||
unsafe extern "C" {
|
||||
#[doc = " @brief Query an NFC parameter value.\n\n The queried value will be placed into the passed data buffer.\n If the buffer is too small, max_data_length will contain the required\n buffer size. If the buffer is big enough, max_data_length will contain\n the actual size of the data.\n\n @param id ID of the parameter to query.\n @param data Pointer to a buffer receiving the queried data.\n @param max_data_length Size of the buffer, receives actual size of queried\n data.\n\n @retval 0 Success.\n @retval -NRF_EINVAL Invalid argument (for example, wrong data length, NULL pointer)."]
|
||||
pub fn nfc_t4t_parameter_get(
|
||||
id: nfc_t4t_param_id_t,
|
||||
data: *mut cty::c_void,
|
||||
max_data_length: *mut usize,
|
||||
) -> cty::c_int;
|
||||
}
|
||||
unsafe extern "C" {
|
||||
#[doc = " @brief Activate the NFC frontend.\n\n Only after calling this function, events will be posted to the application\n callback.\n\n @retval 0 Success.\n @retval -NRF_EOPNOTSUPP Already started."]
|
||||
pub fn nfc_t4t_emulation_start() -> cty::c_int;
|
||||
}
|
||||
unsafe extern "C" {
|
||||
#[doc = " @brief Deactivate the NFC frontend.\n\n After calling this function, no more events will be posted to the application\n callback.\n\n @retval 0 Success.\n @retval -NRF_EOPNOTSUPP Emulation was already stopped."]
|
||||
pub fn nfc_t4t_emulation_stop() -> cty::c_int;
|
||||
}
|
||||
unsafe extern "C" {
|
||||
#[doc = " @brief Release reference to application callback.\n\n After calling this function, the passed callback pointer is no longer\n considered valid.\n After calling this function, the passed ndef pointer is no longer\n considered valid.\n\n You need to restart with @ref nfc_t4t_setup to run a new Emulation.\n\n @retval 0 Success.\n @retval -NRF_EOPNOTSUPP The NFC T4T has been de-initialized already."]
|
||||
pub fn nfc_t4t_done() -> cty::c_int;
|
||||
}
|
||||
+552
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,15 @@
|
||||
[build]
|
||||
target = "thumbv7em-none-eabihf"
|
||||
|
||||
[target.thumbv7em-none-eabihf]
|
||||
# cortex-m-rt 0.7+ injects -Tlink.x itself via build.rs; nrf52840-hal's build.rs
|
||||
# adds memory.x to the link search path. Don't duplicate either here.
|
||||
rustflags = [
|
||||
"-C", "linker=flip-link",
|
||||
]
|
||||
|
||||
[env]
|
||||
# defmt 1.x defaults to Error level when DEFMT_LOG is unset — info!/debug!/trace!
|
||||
# get compiled to nothing and the RTT buffer stays silent. Pin it to info for
|
||||
# this runner so bring-up logs (USB init, NFCT state machine, etc.) reach RTT.
|
||||
DEFMT_LOG = "info"
|
||||
@@ -0,0 +1,86 @@
|
||||
[package]
|
||||
name = "runner-nrf52840dk"
|
||||
version.workspace = true
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
description = "Solo2 firmware port to Nordic nRF52840-DK"
|
||||
|
||||
[[bin]]
|
||||
name = "runner-nrf52840dk"
|
||||
path = "src/main.rs"
|
||||
|
||||
[features]
|
||||
default = ["board-dk"]
|
||||
# Pick exactly one of these to target a board. Mutually exclusive — see
|
||||
# the compile_error! in src/board/mod.rs.
|
||||
board-dk = [] # Nordic nRF52840-DK (PCA10056) dev board
|
||||
board-solo = [] # SoloKeys Micro USB custom board
|
||||
|
||||
# nRF52840 USB+NFC coexistence is broken at the hardware level (anomaly 190
|
||||
# + DMA/clock arbitration). Enabling this turns on USB CCID + PIV + OpenPGP
|
||||
# at the cost of NFC; default off keeps NFC working.
|
||||
ccid-on-nfc-off = []
|
||||
|
||||
# Replaces button-driven user presence with a probe-rs-writable static
|
||||
# (`UP_CONTROL` in `board::mod`). Used by the integration tests in
|
||||
# `runners/pc/tests` to drive `approve`/`deny` from the host over JTAG.
|
||||
# Off by default; NEVER enable on firmware shipped to users.
|
||||
test-up-control = []
|
||||
|
||||
[dependencies]
|
||||
cortex-m .workspace = true
|
||||
cortex-m-rt = "0.7"
|
||||
defmt .workspace = true
|
||||
defmt-rtt .workspace = true
|
||||
panic-halt .workspace = true
|
||||
rtic = { version = "2.0.0", features = ["thumbv7-backend"] }
|
||||
rtic-monotonics .workspace = true
|
||||
rtic-sync .workspace = true
|
||||
embedded-time = "0.12"
|
||||
|
||||
embedded-hal .workspace = true
|
||||
embedded-storage = "0.3"
|
||||
|
||||
# USB + CTAPHID + APDU dispatch
|
||||
usb-device .workspace = true
|
||||
usbd-ctaphid .workspace = true
|
||||
usbd-ccid .workspace = true
|
||||
ctaphid-dispatch .workspace = true
|
||||
apdu-dispatch .workspace = true
|
||||
interchange .workspace = true
|
||||
|
||||
# NFC stack — chip layer (libnrfx_nfct.a) + Type 4 Tag library
|
||||
# (libnfc_t4t.a) + Rust platform glue.
|
||||
nrf-nfc .workspace = true
|
||||
|
||||
# Trussed + storage + apps
|
||||
littlefs2 .workspace = true
|
||||
# `mldsa44` (CTAP 2.3) is opt-in per runner — see workspace Cargo.toml.
|
||||
# DK has plenty of headroom; LPC55 doesn't fit it.
|
||||
trussed = { workspace = true, features = ["mldsa44"] }
|
||||
trussed-core = { workspace = true, features = ["mldsa44"] }
|
||||
trussed-staging .workspace = true
|
||||
trussed-fs-info .workspace = true
|
||||
trussed-hkdf .workspace = true
|
||||
trussed-manage .workspace = true
|
||||
trussed-chunked .workspace = true
|
||||
trussed-hpke .workspace = true
|
||||
trussed-wrap-key-to-file .workspace = true
|
||||
trussed-auth .workspace = true
|
||||
trussed-auth-backend .workspace = true
|
||||
fido-authenticator = { workspace = true, features = ["mldsa44"] }
|
||||
admin-app .workspace = true
|
||||
ndef-app .workspace = true
|
||||
secrets-app .workspace = true
|
||||
piv-authenticator .workspace = true
|
||||
opcard .workspace = true
|
||||
heapless .workspace = true
|
||||
generic-array = "0.14"
|
||||
static_cell .workspace = true
|
||||
|
||||
# nRF52840 HAL/PAC. Pinned for usb-device 0.2 + usbd-ctaphid 0.4 compatibility:
|
||||
# nrf-usbd 0.1 is the only usb-device 0.2-compatible nRF USB driver, and it
|
||||
# pairs with nrf52840-hal 0.15.1. nrf-hal-common 0.15.1 accepts cortex-m-rt 0.7.
|
||||
nrf52840-hal = "0.15.1"
|
||||
nrf52840-pac = "0.11"
|
||||
nrf-usbd = "0.1"
|
||||
@@ -0,0 +1,145 @@
|
||||
.PHONY: build build-dk build-solo build-dk-test flash flash-jtag flash-jtag-ccid flash-jtag-test flash-set-key bacon clean-dfu
|
||||
|
||||
# ── Paths ─────────────────────────────────────────────────────────────────────
|
||||
ELF := ../../target/thumbv7em-none-eabihf/release/runner-nrf52840dk
|
||||
APP_HEX := $(ELF).hex
|
||||
|
||||
DFU_DIR := dfu
|
||||
# Prefer prod artifacts if they exist (made by `make flash-set-key`),
|
||||
# fall back to the committed dev key + bootloader.
|
||||
DFU_KEY := $(if $(wildcard $(DFU_DIR)/prod.pem),$(DFU_DIR)/prod.pem,$(DFU_DIR)/debug.pem)
|
||||
BOOT_HEX := $(if $(wildcard $(DFU_DIR)/bootloader_prod.hex),$(DFU_DIR)/bootloader_prod.hex,$(DFU_DIR)/bootloader.hex)
|
||||
# MBR is a separate hex (~4 KB) — not bundled in the bootloader's own hex.
|
||||
# Lives at 0x0; jumps to bootloader at UICR.NRFFW[0] = 0xF4000.
|
||||
MBR_HEX := $(DFU_DIR)/mbr.hex
|
||||
|
||||
# nrfutil DFU port — override on cmdline if auto-detect picks the wrong one.
|
||||
# The DK exposes two tty.usbmodem* ports for J-Link OB's own VCP (serial
|
||||
# starts with `001050...` on PCA10056). Filter those out so we hit the
|
||||
# chip's USB CDC — that's the bootloader (VID 0x1915 PID 0x521F) when in
|
||||
# DFU mode, or the app's CDC when in app mode.
|
||||
NRF_PORT ?= $(shell ls /dev/tty.usbmodem* 2>/dev/null | grep -v "tty.usbmodem001050" | head -1)
|
||||
|
||||
# Nordic's Python nrfutil — `pip3 install --user --break-system-packages nrfutil`.
|
||||
# Adafruit's fork dropped the `pkg`/`settings` subcommands we need; use upstream.
|
||||
# nrfutil 5.2.0 is the last working version; 6.x has dependencies (pc-ble-driver-py)
|
||||
# without wheels for modern Python. On Python 3.14 you also need the patches in
|
||||
# dfu/README.md applied to nordicsemi/dfu/signing.py.
|
||||
PATH := $(HOME)/Library/Python/3.14/bin:$(PATH)
|
||||
NRFUTIL := nrfutil
|
||||
|
||||
APP_VER ?= 1
|
||||
HW_VER := 52
|
||||
|
||||
# ── Build targets ─────────────────────────────────────────────────────────────
|
||||
# `build` builds whatever the default Cargo features pick (= board-dk).
|
||||
# `build-dk` and `build-solo` force a specific board; subsequent flash targets
|
||||
# are board-agnostic — they flash whatever's currently in $(ELF).
|
||||
build: build-dk
|
||||
|
||||
build-dk:
|
||||
cargo build --release --no-default-features --features board-dk
|
||||
|
||||
build-solo:
|
||||
cargo build --release --no-default-features --features board-solo
|
||||
|
||||
# Builds with `test-up-control` on, which adds the `UP_CONTROL` static
|
||||
# the host-side test harness writes via probe-rs to drive user-presence
|
||||
# approvals. Otherwise identical to `build-dk`. NEVER ship this build.
|
||||
build-dk-test:
|
||||
cargo build --release --no-default-features --features board-dk,test-up-control
|
||||
|
||||
# ── DFU upgrade (the common case) ─────────────────────────────────────────────
|
||||
# Assumes bootloader is already installed via `make flash-jtag`. App must be
|
||||
# in DFU mode — either via admin "enter DFU" command, or hold Button 4 at
|
||||
# reset to enter via the bootloader's built-in trigger.
|
||||
flash:
|
||||
@if [ ! -f "$(ELF)" ]; then echo "ERROR: no ELF at $(ELF) — run 'make build-dk' or 'make build-solo' first"; exit 1; fi
|
||||
arm-none-eabi-objcopy -O ihex $(ELF) $(APP_HEX)
|
||||
$(NRFUTIL) pkg generate \
|
||||
--hw-version $(HW_VER) \
|
||||
--sd-req 0 \
|
||||
--application-version $(APP_VER) \
|
||||
--application $(APP_HEX) \
|
||||
--key-file $(DFU_KEY) \
|
||||
/tmp/firmware.zip
|
||||
@if [ -z "$(NRF_PORT)" ]; then \
|
||||
echo "ERROR: no /dev/tty.usbmodem* found. Is the device in DFU mode?"; \
|
||||
exit 1; \
|
||||
fi
|
||||
@echo "Using port $(NRF_PORT) (override with NRF_PORT=...)"
|
||||
$(NRFUTIL) dfu usb-serial -pkg /tmp/firmware.zip -p $(NRF_PORT) -b 115200
|
||||
|
||||
# ── Initial install via JLink (one-shot per device, also for recovery) ────────
|
||||
# nRF USB+NFC coexistence is broken at the hardware level (anomaly 199 +
|
||||
# DMA arbitration). Default build: NFC works, no CCID/PIV/OpenPGP over USB.
|
||||
# `make flash-jtag-ccid` adds those at the cost of NFC.
|
||||
flash-jtag: $(BOOT_HEX)
|
||||
@if [ ! -f "$(ELF)" ]; then echo "ERROR: no ELF at $(ELF) — run 'make build-dk' or 'make build-solo' first"; exit 1; fi
|
||||
cp $(ELF) $(ELF).elf
|
||||
arm-none-eabi-objcopy -O ihex $(ELF) $(APP_HEX)
|
||||
$(NRFUTIL) settings generate \
|
||||
--family NRF52840 \
|
||||
--application $(APP_HEX) \
|
||||
--application-version $(APP_VER) \
|
||||
--bootloader-version 1 \
|
||||
--bl-settings-version 2 \
|
||||
/tmp/settings.hex
|
||||
@printf 'r\nhalt\nerase\nloadfile %s\nloadfile %s\nloadfile %s\nloadfile /tmp/settings.hex\nr\ng\nq\n' \
|
||||
"$(MBR_HEX)" "$(BOOT_HEX)" "$(APP_HEX)" > /tmp/flash-jtag.jlink
|
||||
JLinkExe -device nRF52840_xxAA -if SWD -speed 4000 -autoconnect 1 \
|
||||
-CommanderScript /tmp/flash-jtag.jlink
|
||||
|
||||
# Build the test-up-control variant + flash via J-Link. The companion
|
||||
# host-side tests (see `runners/pc/scripts/device_test.sh`) drive UP via
|
||||
# `probe-rs write` against `UP_CONTROL`. NEVER ship.
|
||||
flash-jtag-test: build-dk-test
|
||||
$(MAKE) flash-jtag
|
||||
|
||||
flash-jtag-ccid:
|
||||
cargo build --release --no-default-features --features board-dk,ccid-on-nfc-off
|
||||
$(MAKE) flash-jtag
|
||||
|
||||
# ── Generate a fresh prod keypair + rebuild bootloader to trust it ────────────
|
||||
# Run once. Output: dfu/prod.pem + dfu/bootloader_prod.hex (both gitignored).
|
||||
# Subsequent `make flash` and `make flash-jtag` automatically prefer these.
|
||||
# Requires NRF5_SDK_ROOT to point at an extracted nRF5 SDK 17.1.0.
|
||||
flash-set-key:
|
||||
@if [ -z "$(NRF5_SDK_ROOT)" ]; then \
|
||||
echo "ERROR: set NRF5_SDK_ROOT to your nRF5 SDK 17.1.0 directory"; \
|
||||
exit 1; \
|
||||
fi
|
||||
$(NRFUTIL) keys generate $(DFU_DIR)/prod.pem
|
||||
@echo "Wrote $(DFU_DIR)/prod.pem"
|
||||
$(NRFUTIL) keys display --key pk --format code --out_file $(DFU_DIR)/dfu_public_key.c $(DFU_DIR)/prod.pem
|
||||
@echo "Wrote $(DFU_DIR)/dfu_public_key.c"
|
||||
# Backup SDK pubkey + linker, swap in ours, build with the same tighter
|
||||
# layout as bootloader.hex (origin 0xF4000, length 0xA000), restore after.
|
||||
cp $(NRF5_SDK_ROOT)/examples/dfu/dfu_public_key.c $(NRF5_SDK_ROOT)/examples/dfu/dfu_public_key.c.bak
|
||||
cp $(DFU_DIR)/dfu_public_key.c $(NRF5_SDK_ROOT)/examples/dfu/dfu_public_key.c
|
||||
cp $(NRF5_SDK_ROOT)/examples/dfu/open_bootloader/pca10056_usb/armgcc/open_bootloader_gcc_nrf52.ld \
|
||||
$(NRF5_SDK_ROOT)/examples/dfu/open_bootloader/pca10056_usb/armgcc/open_bootloader_gcc_nrf52.ld.bak
|
||||
sed -i.bak 's|FLASH (rx) : ORIGIN = 0xe0000, LENGTH = 0x1e000|FLASH (rx) : ORIGIN = 0xf4000, LENGTH = 0xa000|' \
|
||||
$(NRF5_SDK_ROOT)/examples/dfu/open_bootloader/pca10056_usb/armgcc/open_bootloader_gcc_nrf52.ld
|
||||
# nRF5 SDK was tested with GCC ~9; modern (15+) is stricter. Disable -Werror.
|
||||
sed -i.werror.bak 's/CFLAGS += -Wall -Werror/CFLAGS += -Wall/' \
|
||||
$(NRF5_SDK_ROOT)/examples/dfu/open_bootloader/pca10056_usb/armgcc/Makefile
|
||||
cd $(NRF5_SDK_ROOT)/examples/dfu/open_bootloader/pca10056_usb/armgcc && \
|
||||
$(MAKE) clean GNU_INSTALL_ROOT=/opt/homebrew/bin/ GNU_VERSION=15.2.1 GNU_PREFIX=arm-none-eabi && \
|
||||
$(MAKE) GNU_INSTALL_ROOT=/opt/homebrew/bin/ GNU_VERSION=15.2.1 GNU_PREFIX=arm-none-eabi
|
||||
cp $(NRF5_SDK_ROOT)/examples/dfu/open_bootloader/pca10056_usb/armgcc/_build/nrf52840_xxaa.hex \
|
||||
$(DFU_DIR)/bootloader_prod.hex
|
||||
# Restore SDK to original.
|
||||
mv $(NRF5_SDK_ROOT)/examples/dfu/dfu_public_key.c.bak $(NRF5_SDK_ROOT)/examples/dfu/dfu_public_key.c
|
||||
mv $(NRF5_SDK_ROOT)/examples/dfu/open_bootloader/pca10056_usb/armgcc/open_bootloader_gcc_nrf52.ld.bak \
|
||||
$(NRF5_SDK_ROOT)/examples/dfu/open_bootloader/pca10056_usb/armgcc/open_bootloader_gcc_nrf52.ld
|
||||
mv $(NRF5_SDK_ROOT)/examples/dfu/open_bootloader/pca10056_usb/armgcc/Makefile.werror.bak \
|
||||
$(NRF5_SDK_ROOT)/examples/dfu/open_bootloader/pca10056_usb/armgcc/Makefile
|
||||
@echo "Done. Now run 'make flash-jtag' to install the prod bootloader + app."
|
||||
|
||||
clean-dfu:
|
||||
rm -f $(DFU_DIR)/prod.pem $(DFU_DIR)/bootloader_prod.hex
|
||||
@echo "Removed prod artifacts. Subsequent flashes use the committed debug key."
|
||||
|
||||
bacon:
|
||||
bacon
|
||||
@@ -0,0 +1,91 @@
|
||||
# solo2 on Nordic nRF52840-DK
|
||||
|
||||
### the first open source FIDO2 security key (on nRF, with NFC)
|
||||
|
||||

|
||||
|
||||
> ⚠️ **Experimental — for developers only.**
|
||||
> SoloKeys does not produce or sell any device using the Nordic nRF52840 chip.
|
||||
> This runner is a research port of the solo2 firmware to the
|
||||
> [nRF52840 Development Kit](https://www.nordicsemi.com/Products/Development-hardware/nRF52840-DK)
|
||||
> for hacking, evaluation, and learning. **Do not** use it as a real
|
||||
> security key — there is no provisioning, no attestation, no hardware
|
||||
> root of trust, and no security review.
|
||||
|
||||
## What works
|
||||
|
||||
- USB CTAPHID — FIDO2 + U2F over USB (`fido-authenticator`)
|
||||
- NFC — FIDO2 + U2F over NFC, plus an NDEF tag pointing at solokeys.com
|
||||
(a URL banner phones with a background NFC scanner can pop on tap)
|
||||
- Storage — internal NVMC at `0x000C_0000` (256 KiB) for trussed-managed
|
||||
credentials; volatile RAM-backed for everything else
|
||||
|
||||
Tested with [webauthn.io](https://webauthn.io) (registration and
|
||||
authentication) on the Nordic nRF52840-DK board.
|
||||
|
||||
## Build
|
||||
|
||||
```
|
||||
make build-nrf
|
||||
```
|
||||
|
||||
(or `cargo build --release` from this directory — cargo needs the
|
||||
runner's `.cargo/config.toml` to pick up `target = thumbv7em-none-eabihf`,
|
||||
so building with `-p` from the workspace root will fail.)
|
||||
|
||||
The output ELF lands at `target/thumbv7em-none-eabihf/release/runner-nrf52840dk`
|
||||
(no `.elf` extension — cargo names the binary after the package).
|
||||
|
||||
## Flash
|
||||
|
||||
You need a J-Link probe (the DK has one onboard) and `JLinkExe`.
|
||||
|
||||
```
|
||||
cd runners/nrf52840dk
|
||||
cp ../../target/thumbv7em-none-eabihf/release/runner-nrf52840dk \
|
||||
../../target/thumbv7em-none-eabihf/release/runner-nrf52840dk.elf
|
||||
JLinkExe -device nRF52840_xxAA -if SWD -speed 4000 -autoconnect 1 \
|
||||
-CommandFile flash.jlink
|
||||
```
|
||||
|
||||
The script halts the chip, loads the ELF, resets, and runs.
|
||||
|
||||
## Live RTT logs
|
||||
|
||||
```
|
||||
JLinkRTTLogger -Device nRF52840_xxAA -If SWD -Speed 4000 -RTTChannel 0 out.log
|
||||
defmt-print -e ../../target/thumbv7em-none-eabihf/release/runner-nrf52840dk.elf < out.log
|
||||
```
|
||||
|
||||
`DEFMT_LOG=info` is set in `.cargo/config.toml`; raise to `debug` for
|
||||
more chatter.
|
||||
|
||||
## Test
|
||||
|
||||
- USB: plug the J2 (USB) connector into a host. Open
|
||||
[webauthn.io](https://webauthn.io), pick "Register", confirm with
|
||||
SW1 or SW2 (any button → user-presence).
|
||||
- NFC: tap the antenna pad on the DK with an NFC-capable phone. A phone
|
||||
running a background NFC scanner should pop a "https://solokeys.com/"
|
||||
banner. For WebAuthn over NFC, open webauthn.io in a browser that
|
||||
supports NFC security keys and choose "Security key" / "NFC" when
|
||||
prompted.
|
||||
|
||||
## NFC stack and the library
|
||||
|
||||
The NFC implementation depends on Nordic's **`libnfc_t4t.a`**
|
||||
(Type 4 Tag library, distributed in [nRF Connect SDK]) — a
|
||||
precompiled, **closed-source** binary blob that handles the ISO 14443-4
|
||||
ISO-DEP layer (anti-collision, RATS/ATS, I-block framing, chaining, WTX).
|
||||
The blob, the chip-layer `libnrfx_nfct.a`, and the platform glue are
|
||||
all in [`components/nrf-nfc/`](../../components/nrf-nfc/); see that
|
||||
crate's `vendor/README.md` for source/version provenance. The runner's
|
||||
`nfct.rs` is a thin Rust wrapper that delivers reassembled APDUs to
|
||||
`apdu-dispatch` and ships responses back through the library.
|
||||
|
||||
If you want a fully open NFC stack, the workspace also has an
|
||||
open-source ISO-DEP layer in
|
||||
[`components/nfc-device`](../../components/nfc-device). It isn't wired
|
||||
into this runner today.
|
||||
|
||||
[nRF Connect SDK]: https://www.nordicsemi.com/Products/Development-software/nRF-Connect-SDK
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user