feat(firmware): add nfc logic add doc corrections

This commit is contained in:
2026-07-15 15:38:31 +02:00
parent dbbf79f7f6
commit a115996e0f
18 changed files with 602 additions and 42 deletions
+5
View File
@@ -25,10 +25,13 @@ The format is based on Keep a Changelog and this project follows Semantic Versio
- Firmware lock control documentation.
- English architecture documentation in `docs/architecture.md`.
- Persistent six-digit access code storage.
- Persistent NFC tag UID storage with default development UID `60:4F:E2:B5`.
- NFC scan-mode application flow triggered by keypad activity.
- Lock control pulse on XIAO pin `D9`.
- Lock state feedback detection using KR-S79 `COM/NC` on XIAO `D7` / `D8`.
- Long buzzer success beep for accepted unlock codes.
- Door opened and door closed UART messages.
- NFC scan and UID validation UART messages.
### Changed
@@ -43,7 +46,9 @@ The format is based on Keep a Changelog and this project follows Semantic Versio
- Aligned firmware documentation with C17 and the current Zephyr build tools.
- Updated project tracking documents to reflect completed RGB LED, GPIO expander, keypad, and active buzzer work.
- Updated keypad unlock user feedback with off-at-rest LEDs, green-open indication, red invalid-code feedback, and `B` entry cancellation.
- Updated runtime LED feedback with blue NFC scan-mode indication.
- Updated open-lock reminder beep interval to 2 seconds.
- Corrected NFC hardware documentation: the nRF52840 integrated NFCT peripheral is tag-side NFC-A hardware, while passive badge UID reading requires a dedicated NFC reader circuit.
### Fixed
+6 -1
View File
@@ -29,6 +29,7 @@ Completed or validated:
- Active buzzer feedback
- Persistent six-digit access codes
- Keypad unlock flow with default development code `784512`
- Persistent NFC tag UID table and scan-mode firmware API
- Lock command pulse on XIAO `D9`
- KR-S79 `COM/NC` lock state feedback on XIAO `D7` / `D8`
- Green-open, off-closed, red-invalid LED feedback
@@ -40,12 +41,13 @@ In progress:
- Original hardware reverse engineering
- Production keypad mapping
- NFC credential reader hardware selection
- Hardware validation
Planned:
- Administrator access management
- NFC
- NFC badge unlock with a dedicated reader circuit
- Battery management
- Zigbee
- OTA updates
@@ -88,6 +90,7 @@ Current firmware modules:
- Lock control
- Lock state feedback
- Persistent access codes
- Persistent NFC tag UID storage
Firmware documentation is available in:
@@ -107,6 +110,8 @@ Current development platform:
- KR-S79 `NC` feedback on XIAO `D7`
- KR-S79 `COM` feedback reference on XIAO `D8`
The XIAO nRF52840 exposes the Nordic NFCT pins (`NFC1/P0.09` and `NFC2/P0.10`). This peripheral is tag-side NFC-A hardware, not a standalone active reader for passive badges. Badge UID reading requires a dedicated NFC reader circuit on the production hardware.
The production hardware is planned around a custom PCB and the original parcel box mechanical parts.
## Documentation
+13 -11
View File
@@ -16,7 +16,7 @@ The firmware is based on Zephyr RTOS and follows a modular architecture to simpl
- No subscription.
- Local-first operation.
- Battery-powered design.
- NFC support.
- NFC badge support through dedicated reader hardware.
- Bluetooth support.
- Zigbee support.
- Home Assistant compatibility.
@@ -43,7 +43,8 @@ The firmware is based on Zephyr RTOS and follows a modular architecture to simpl
| Door or lock state feedback | Done |
| Persistent access code storage | Done |
| Battery driver | Pending |
| NFC driver | Pending |
| NFC credential storage and scan API | Done |
| Dedicated NFC reader driver | Pending |
| Power management | Pending |
| Bluetooth configuration | Pending |
| Zigbee integration | Pending |
@@ -118,7 +119,7 @@ Components:
- Lock command pulse.
- Door or lock state feedback through the KR-S79 `COM/NC` contact.
- Battery monitoring.
- NFC antenna.
- Dedicated NFC reader circuit and antenna.
- Buzzer.
- External LEDs.
@@ -148,7 +149,8 @@ Components:
- Persistent six-digit access codes.
- Battery.
- Buzzer.
- NFC.
- NFC credential storage.
- Dedicated NFC reader backend.
Security:
@@ -170,7 +172,7 @@ Features:
- Deep sleep.
- Wake-up on keypad.
- Wake-up on NFC.
- Wake-up on dedicated NFC reader.
- Battery monitoring.
- Low battery warning.
@@ -186,7 +188,7 @@ Features:
- Initial pairing.
- Administrator PIN configuration.
- NFC enrollment.
- NFC badge enrollment.
- Device information.
- Firmware information.
@@ -205,7 +207,7 @@ Required features:
- Door or lock state feedback.
- Battery monitoring.
- Administrator PIN.
- Administrator NFC badge.
- Administrator NFC badge through dedicated reader hardware.
- Bluetooth configuration.
- No cloud.
- No subscription.
@@ -251,7 +253,7 @@ Features:
- User creation.
- User deletion.
- Permanent PINs.
- Permanent NFC badges.
- Permanent NFC badges through dedicated reader hardware.
- User permissions.
Status: planned.
@@ -265,7 +267,7 @@ Objective: store important events locally.
Events:
- PIN unlock.
- NFC unlock.
- NFC unlock through dedicated reader hardware.
- Invalid PIN.
- Invalid badge.
- Low battery.
@@ -328,7 +330,7 @@ Features:
- Expiration time.
- Usage counter.
- One-time PINs.
- Temporary NFC badges.
- Temporary NFC badges through dedicated reader hardware.
Status: planned.
@@ -388,7 +390,7 @@ Expected features:
- Standalone firmware.
- Battery-powered operation.
- Bluetooth.
- NFC.
- NFC badge support through dedicated reader hardware.
- Zigbee.
- Home Assistant.
- Flutter application.
+6 -5
View File
@@ -111,9 +111,10 @@ Tasks are grouped by development phase and updated throughout the project.
### NFC
- [ ] Design antenna.
- [ ] Validate tuning network.
- [ ] Read UID.
- [ ] Select dedicated NFC reader IC.
- [ ] Design reader antenna.
- [ ] Validate reader tuning network.
- [ ] Read UID through the dedicated reader.
- [ ] Detect badge removal.
### Buzzer
@@ -156,7 +157,7 @@ Tasks are grouped by development phase and updated throughout the project.
- [ ] Battery warnings.
- [ ] Sleep mode.
- [ ] Wake on keypad.
- [ ] Wake on NFC.
- [ ] Wake on dedicated NFC reader.
- [ ] Measure sleep current.
- [ ] Measure battery life.
@@ -169,7 +170,7 @@ Tasks are grouped by development phase and updated throughout the project.
- [x] Door or lock feedback.
- [ ] Battery monitoring.
- [ ] Administrator PIN.
- [ ] Administrator NFC badge.
- [ ] Administrator NFC badge through dedicated reader hardware.
- [x] Audible feedback.
- [ ] Standalone operation.
- [ ] Battery-powered operation.
+3 -2
View File
@@ -80,7 +80,7 @@ The system is centered around one microcontroller:
Responsibilities:
- Keypad scanning.
- NFC reading.
- NFC credential coordination.
- Lock control.
- Battery monitoring.
- RGB LED status.
@@ -113,10 +113,11 @@ The firmware is organized into independent modules.
### NFC
- Badge reading.
- UID validation.
- Low-power wake-up.
The nRF52840 integrated NFCT peripheral is tag-side NFC-A hardware. Passive badge UID reading requires a dedicated NFC reader circuit on the production hardware.
### Access Control
- Administrator codes.
+6 -3
View File
@@ -58,6 +58,7 @@ The onboard RGB LED is used to quickly identify the firmware state.
| ------- | ----------------------------------- |
| Off | Idle / lock closed |
| Green | Lock state feedback reports open |
| Blue | NFC credential scan mode active |
| Red | Invalid six-digit access code |
| Magenta | Fatal initialization error |
@@ -101,11 +102,13 @@ Door opened
Door closed
```
Future NFC module:
Future dedicated NFC reader backend:
```text
NFC tag detected.
UID: xx xx xx xx
Scan NFC: ON
NFC detected: 60:4F:E2:B5
NFC valid
Scan NFC: OFF
```
---
+4 -1
View File
@@ -49,10 +49,13 @@ The main loop collects numeric keypad input.
- Up to 10 codes can be stored.
- Codes are persisted through Zephyr settings with the NVS backend.
- The development default code is `784512`.
- A valid six-digit entry is the only current path that triggers `lock_control_open()`.
- A valid six-digit entry triggers `lock_control_open()`.
- A future dedicated NFC reader backend may trigger `lock_control_open()` after a valid stored tag UID is detected.
- `*`, `#`, and `B` clear the current entry.
- A valid six-digit entry triggers one long success beep before the opening pulse.
- An invalid six-digit entry triggers three short close beeps and keeps the red LED on for 1 second.
- NFC credential scan mode starts on keypad activity, remains active for 1 minute, and is shown with the blue LED.
- A valid NFC tag UID will use the same success beep and lock opening path as a valid keypad code once the dedicated reader backend is added.
- The green LED stays on while the lock state feedback reports the lock open.
- A short reminder beep is emitted every 2 seconds while the lock state feedback reports open.
- Door state changes are reported over UART as `Door opened` and `Door closed`.
+67
View File
@@ -0,0 +1,67 @@
# NFC
## Purpose
This module provides the application-level NFC credential flow and persistent NFC tag UID storage.
NFC tag UIDs are stored in non-volatile settings, like access codes. They remain available after power loss and expose add, replace, and clear APIs for the future mobile application and Home Assistant integration.
The Seeed Studio XIAO nRF52840 exposes the Nordic NFCT pins (`NFC1/P0.09` and `NFC2/P0.10`). The integrated NFCT peripheral is tag-side NFC-A hardware and is not a standalone active reader for passive badges.
Passive badge UID reading requires a dedicated NFC reader circuit on the production hardware.
---
## Persistent Tags
- Up to 10 NFC tag UIDs can be stored.
- UID length can be 1 to 10 bytes.
- The first default development UID is `60:4F:E2:B5`.
- A valid stored table can contain zero enabled tags. This allows future applications to delete all tags without having the default test UID recreated after reboot.
Public API:
```c
int nfc_tags_init(void);
bool nfc_tags_is_valid(const uint8_t *uid, size_t length);
int nfc_tags_set(size_t slot, const uint8_t *uid, size_t length);
int nfc_tags_clear(size_t slot);
```
---
## Scan Mode
The firmware keeps the NFC credential scan flow disabled by default.
The main loop enables scan mode when a keypad key is pressed. Scan mode remains active for 1 minute after the latest key press, then the firmware disables NFC credential scanning again.
While scan mode is active, the RGB LED is blue.
When a future NFC reader backend detects a tag:
- The UID is printed over UART.
- A valid UID triggers the same unlock path as a valid keypad code: success beep, lock open pulse, and regular lock state feedback.
- After a valid NFC unlock through the dedicated reader backend, scan mode is disabled immediately.
- An invalid UID is reported over UART and scan mode remains active until timeout or a valid tag.
Runtime UART messages:
```text
Scan NFC: ON
Scan NFC: OFF
NFC detected: 60:4F:E2:B5
NFC valid
NFC not valid
```
---
## Current Driver Status
The current `nfc` module defines the scan-mode API and keeps NFC disabled at startup.
The hardware-specific tag detection backend is still a placeholder. It currently returns no detected UID until a dedicated NFC reader implementation is added.
+9 -1
View File
@@ -95,6 +95,12 @@ KR-S79 `COM/NC` feedback contact detection using `NC` on XIAO `D7` and `COM` on
Persistent storage for up to 10 six-digit unlock codes.
### NFC Tags
Persistent storage for NFC tag UIDs and the application-level scan-mode API.
The XIAO nRF52840 integrated NFCT peripheral is tag-side NFC-A hardware. Passive badge UID reading will require a dedicated NFC reader backend.
---
## Development Philosophy
@@ -122,6 +128,8 @@ Implemented:
- Long success beep on valid access code.
- Three short beeps on invalid access code.
- Persistent six-digit access code storage.
- Persistent NFC tag UID storage with default development UID `60:4F:E2:B5`.
- NFC credential scan-mode API enabled for 1 minute after keypad activity, with blue LED feedback.
- Lock command pulse on XIAO pin `D9`.
- Lock state feedback through the KR-S79 `COM/NC` contact.
- Door opened / closed debug output.
@@ -131,6 +139,6 @@ In progress or planned:
- Production keypad mapping.
- Battery monitoring.
- NFC.
- Dedicated NFC reader backend for passive badge UID detection.
- Zigbee.
- OTA updates.
+2
View File
@@ -14,7 +14,9 @@ target_sources(app PRIVATE
src/buzzer.c
src/lock_control.c
src/access_codes.c
src/nfc_tags.c
src/lock_state.c
src/nfc.c
src/gpio_expander.c
src/keypad.c
)
+97 -7
View File
@@ -20,6 +20,8 @@
#include "led.h"
#include "lock_control.h"
#include "lock_state.h"
#include "nfc.h"
#include "nfc_tags.h"
#include <zephyr/kernel.h>
@@ -31,6 +33,7 @@
#define MAIN_LOOP_DELAY_MS 20
#define KEY_PRESS_LED_MS 100
#define NFC_SCAN_TIMEOUT_MS 60000
#define LOCK_OPEN_BEEP_INTERVAL_MS 2000
#define INVALID_CODE_LED_MS 1000
#define INVALID_CODE_BEEP_COUNT 3
@@ -44,8 +47,10 @@
* Private helpers
* -------------------------------------------------------------------------- */
static void set_lock_led(bool lock_open) {
if (lock_open) {
static void set_status_led(bool lock_open, bool nfc_scan_active) {
if (nfc_scan_active) {
led_set_blue();
} else if (lock_open) {
led_set_green();
} else {
led_off();
@@ -54,6 +59,30 @@ static void set_lock_led(bool lock_open) {
static bool key_is_digit(char key) { return key >= '0' && key <= '9'; }
static void print_nfc_uid(const uint8_t *uid, size_t length) {
for (size_t i = 0; i < length; i++) {
printf("%02X", uid[i]);
if (i < (length - 1)) {
printf(":");
}
}
}
static void stop_nfc_scan(bool *nfc_scan_active, bool lock_open) {
if (!*nfc_scan_active) {
return;
}
if (nfc_scan_disable() < 0) {
printf("NFC scan disable failed\n");
}
*nfc_scan_active = false;
printf("Scan NFC: OFF\n");
set_status_led(lock_open, *nfc_scan_active);
}
static void signal_invalid_code(void) {
led_set_red();
@@ -81,6 +110,10 @@ int main(void) {
int64_t next_lock_open_beep_ms;
char entered_code[ACCESS_CODE_LENGTH];
size_t entered_code_length;
bool nfc_scan_active;
int64_t nfc_scan_deadline_ms;
uint8_t nfc_uid[NFC_TAG_UID_MAX_LENGTH];
size_t nfc_uid_length;
if (led_init() < 0) {
return 0;
@@ -120,6 +153,22 @@ int main(void) {
}
}
if (nfc_tags_init() < 0) {
led_set_magenta();
while (1) {
k_msleep(1000);
}
}
if (nfc_init() < 0) {
led_set_magenta();
while (1) {
k_msleep(1000);
}
}
if (keypad_init() < 0) {
led_set_magenta();
@@ -132,22 +181,25 @@ int main(void) {
previous_lock_open = lock_open;
next_lock_open_beep_ms = k_uptime_get();
entered_code_length = 0;
nfc_scan_active = false;
nfc_scan_deadline_ms = 0;
set_lock_led(lock_open);
set_status_led(lock_open, nfc_scan_active);
printf("\n");
printf("========================================\n");
printf("OpenParcelBox Firmware\n");
printf("Hardware Test: RGB LED + Buzzer + Lock + Keypad\n");
printf("Hardware Test: RGB LED + Buzzer + Lock + Keypad + NFC\n");
printf("========================================\n");
printf("Scan NFC: OFF\n");
set_lock_led(lock_open);
set_status_led(lock_open, nfc_scan_active);
while (1) {
lock_open = lock_state_is_open();
if (lock_open != previous_lock_open) {
set_lock_led(lock_open);
set_status_led(lock_open, nfc_scan_active);
previous_lock_open = lock_open;
if (lock_open) {
@@ -163,12 +215,48 @@ int main(void) {
next_lock_open_beep_ms = k_uptime_get() + LOCK_OPEN_BEEP_INTERVAL_MS;
}
if (nfc_scan_active && k_uptime_get() >= nfc_scan_deadline_ms) {
stop_nfc_scan(&nfc_scan_active, lock_open);
}
if (nfc_scan_active &&
nfc_read_detected_uid(nfc_uid, sizeof(nfc_uid), &nfc_uid_length)) {
printf("NFC detected: ");
print_nfc_uid(nfc_uid, nfc_uid_length);
printf("\n");
if (nfc_tags_is_valid(nfc_uid, nfc_uid_length)) {
printf("NFC valid\n");
buzzer_beep_success();
if (lock_control_open() < 0) {
printf("Lock control open failed\n");
}
stop_nfc_scan(&nfc_scan_active, lock_state_is_open());
} else {
printf("NFC not valid\n");
}
}
key = keypad_get_key();
if (key != 0) {
printf("Key pressed: %c\n", key);
if (!nfc_scan_active) {
if (nfc_scan_enable() < 0) {
printf("NFC scan enable failed\n");
} else {
nfc_scan_active = true;
printf("Scan NFC: ON\n");
}
}
nfc_scan_deadline_ms = k_uptime_get() + NFC_SCAN_TIMEOUT_MS;
set_status_led(lock_open, nfc_scan_active);
if (!lock_open) {
if (key == '*' || key == '#' || key == 'B') {
entered_code_length = 0;
@@ -185,6 +273,8 @@ int main(void) {
if (lock_control_open() < 0) {
printf("Lock control open failed\n");
}
stop_nfc_scan(&nfc_scan_active, lock_state_is_open());
} else {
printf("Invalid access code\n");
signal_invalid_code();
@@ -202,7 +292,7 @@ int main(void) {
k_msleep(KEY_PRESS_LED_MS);
set_lock_led(lock_state_is_open());
set_status_led(lock_state_is_open(), nfc_scan_active);
}
}
+42
View File
@@ -0,0 +1,42 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* OpenParcelBox
* Copyright (c) 2026
*
* NFC scan mode interface.
*/
#include "nfc.h"
#include <errno.h>
#include <zephyr/sys/util.h>
static bool scan_enabled;
int nfc_init(void) {
scan_enabled = false;
return 0;
}
int nfc_scan_enable(void) {
scan_enabled = true;
return 0;
}
int nfc_scan_disable(void) {
scan_enabled = false;
return 0;
}
bool nfc_scan_is_enabled(void) { return scan_enabled; }
bool nfc_read_detected_uid(uint8_t *uid, size_t uid_capacity,
size_t *uid_length) {
ARG_UNUSED(uid);
ARG_UNUSED(uid_capacity);
ARG_UNUSED(uid_length);
return false;
}
+61
View File
@@ -0,0 +1,61 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* OpenParcelBox
* Copyright (c) 2026
*
* NFC scan mode interface.
*/
#ifndef NFC_H
#define NFC_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "nfc_tags.h"
/**
* @brief Initialize the NFC driver.
*
* The NFC field is left disabled after initialization.
*
* @return 0 on success, negative value on error.
*/
int nfc_init(void);
/**
* @brief Enable NFC scan mode.
*
* @return 0 on success, negative value on error.
*/
int nfc_scan_enable(void);
/**
* @brief Disable NFC scan mode.
*
* @return 0 on success, negative value on error.
*/
int nfc_scan_disable(void);
/**
* @brief Return whether NFC scan mode is currently enabled.
*
* @return true when scan mode is enabled.
*/
bool nfc_scan_is_enabled(void);
/**
* @brief Read one detected NFC tag UID.
*
* @param uid Buffer receiving UID bytes.
* @param uid_capacity Size of the UID buffer.
* @param uid_length Number of UID bytes copied into uid.
*
* @return true when a tag UID was available.
*/
bool nfc_read_detected_uid(uint8_t *uid, size_t uid_capacity,
size_t *uid_length);
#endif /* NFC_H */
+201
View File
@@ -0,0 +1,201 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* OpenParcelBox
* Copyright (c) 2026
*
* Persistent NFC tag UID storage.
*/
#include "nfc_tags.h"
#include <errno.h>
#include <stdint.h>
#include <string.h>
#include <zephyr/settings/settings.h>
#define NFC_TAGS_SETTINGS_ROOT "nfc_tags"
#define NFC_TAGS_SETTINGS_TABLE "table"
#define NFC_TAGS_SETTINGS_TABLE_PATH "nfc_tags/table"
#define NFC_TAGS_MAGIC 0x4f504254U
#define NFC_TAGS_VERSION 1U
struct nfc_tag_slot {
bool enabled;
uint8_t length;
uint8_t uid[NFC_TAG_UID_MAX_LENGTH];
};
struct nfc_tag_table {
uint32_t magic;
uint16_t version;
uint16_t count;
struct nfc_tag_slot slots[NFC_TAG_MAX_COUNT];
};
static const uint8_t default_test_uid[] = {0x60, 0x4f, 0xe2, 0xb5};
static struct nfc_tag_table tag_table;
static bool tag_table_loaded;
static bool nfc_tag_uid_length_is_valid(size_t length) {
return length > 0 && length <= NFC_TAG_UID_MAX_LENGTH;
}
static bool nfc_tag_slot_is_valid(const struct nfc_tag_slot *slot) {
if (!slot->enabled) {
return true;
}
return nfc_tag_uid_length_is_valid(slot->length);
}
static bool nfc_tag_table_is_valid(const struct nfc_tag_table *table) {
size_t enabled_count = 0;
if (table->magic != NFC_TAGS_MAGIC || table->version != NFC_TAGS_VERSION ||
table->count > NFC_TAG_MAX_COUNT) {
return false;
}
for (size_t i = 0; i < NFC_TAG_MAX_COUNT; i++) {
if (!nfc_tag_slot_is_valid(&table->slots[i])) {
return false;
}
if (table->slots[i].enabled) {
enabled_count++;
}
}
return enabled_count == table->count;
}
static void nfc_tags_set_default_table(void) {
memset(&tag_table, 0, sizeof(tag_table));
tag_table.magic = NFC_TAGS_MAGIC;
tag_table.version = NFC_TAGS_VERSION;
tag_table.count = 1;
tag_table.slots[0].enabled = true;
tag_table.slots[0].length = sizeof(default_test_uid);
memcpy(tag_table.slots[0].uid, default_test_uid, sizeof(default_test_uid));
}
static int nfc_tags_save(void) {
return settings_save_one(NFC_TAGS_SETTINGS_TABLE_PATH, &tag_table,
sizeof(tag_table));
}
static int nfc_tags_settings_set(const char *key, size_t len,
settings_read_cb read_cb, void *cb_arg) {
struct nfc_tag_table loaded_table;
ssize_t bytes_read;
if (strcmp(key, NFC_TAGS_SETTINGS_TABLE) != 0) {
return -ENOENT;
}
if (len != sizeof(loaded_table)) {
return -EINVAL;
}
bytes_read = read_cb(cb_arg, &loaded_table, sizeof(loaded_table));
if (bytes_read != sizeof(loaded_table)) {
return -EIO;
}
if (!nfc_tag_table_is_valid(&loaded_table)) {
return 0;
}
tag_table = loaded_table;
tag_table_loaded = true;
return 0;
}
static struct settings_handler nfc_tags_settings = {
.name = NFC_TAGS_SETTINGS_ROOT,
.h_set = nfc_tags_settings_set,
};
int nfc_tags_init(void) {
int ret;
nfc_tags_set_default_table();
tag_table_loaded = false;
ret = settings_register(&nfc_tags_settings);
if (ret < 0) {
return ret;
}
ret = settings_load_subtree(NFC_TAGS_SETTINGS_ROOT);
if (ret < 0) {
return ret;
}
if (!tag_table_loaded || !nfc_tag_table_is_valid(&tag_table)) {
nfc_tags_set_default_table();
return nfc_tags_save();
}
return 0;
}
bool nfc_tags_is_valid(const uint8_t *uid, size_t length) {
if (uid == NULL || !nfc_tag_uid_length_is_valid(length)) {
return false;
}
for (size_t i = 0; i < NFC_TAG_MAX_COUNT; i++) {
if (!tag_table.slots[i].enabled) {
continue;
}
if (tag_table.slots[i].length == length &&
memcmp(tag_table.slots[i].uid, uid, length) == 0) {
return true;
}
}
return false;
}
int nfc_tags_set(size_t slot, const uint8_t *uid, size_t length) {
if (slot >= NFC_TAG_MAX_COUNT || uid == NULL ||
!nfc_tag_uid_length_is_valid(length)) {
return -EINVAL;
}
if (!tag_table.slots[slot].enabled) {
tag_table.count++;
}
tag_table.slots[slot].enabled = true;
tag_table.slots[slot].length = length;
memset(tag_table.slots[slot].uid, 0, sizeof(tag_table.slots[slot].uid));
memcpy(tag_table.slots[slot].uid, uid, length);
return nfc_tags_save();
}
int nfc_tags_clear(size_t slot) {
if (slot >= NFC_TAG_MAX_COUNT) {
return -EINVAL;
}
if (!tag_table.slots[slot].enabled) {
return 0;
}
tag_table.slots[slot].enabled = false;
tag_table.slots[slot].length = 0;
memset(tag_table.slots[slot].uid, 0, sizeof(tag_table.slots[slot].uid));
tag_table.count--;
return nfc_tags_save();
}
+60
View File
@@ -0,0 +1,60 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* OpenParcelBox
* Copyright (c) 2026
*
* Persistent NFC tag UID storage.
*/
#ifndef NFC_TAGS_H
#define NFC_TAGS_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#define NFC_TAG_UID_MAX_LENGTH 10
#define NFC_TAG_MAX_COUNT 10
/**
* @brief Initialize persistent NFC tag UID storage.
*
* Loads stored NFC tag UIDs from non-volatile settings. If no valid table
* exists yet, the development test UID 60:4F:E2:B5 is stored in slot 0.
*
* @return 0 on success, negative value on error.
*/
int nfc_tags_init(void);
/**
* @brief Validate an NFC tag UID.
*
* @param uid UID bytes.
* @param length Number of UID bytes.
*
* @return true when the UID matches an enabled slot.
*/
bool nfc_tags_is_valid(const uint8_t *uid, size_t length);
/**
* @brief Store or replace an NFC tag UID in a slot.
*
* @param slot Slot index from 0 to NFC_TAG_MAX_COUNT - 1.
* @param uid UID bytes.
* @param length Number of UID bytes.
*
* @return 0 on success, negative value on error.
*/
int nfc_tags_set(size_t slot, const uint8_t *uid, size_t length);
/**
* @brief Disable one stored NFC tag UID slot.
*
* @param slot Slot index from 0 to NFC_TAG_MAX_COUNT - 1.
*
* @return 0 on success, negative value on error.
*/
int nfc_tags_clear(size_t slot);
#endif /* NFC_TAGS_H */
+12 -7
View File
@@ -39,12 +39,15 @@ The original keypad PCB is replaced by a new PCB compatible with the original fr
## NFC
The preferred NFC design uses the controller integrated in the nRF52840.
The nRF52840 integrated NFCT peripheral is tag-side NFC-A hardware and is not a standalone active reader for passive badges.
Badge UID reading requires a dedicated NFC reader circuit on the production PCB.
| Description | Quantity | Status |
| --- | --- | --- |
| NFC antenna, 13.56 MHz | 1 | To design |
| NFC matching network | 1 | To design |
| NFC reader IC | 1 | To select |
| NFC reader antenna, 13.56 MHz | 1 | To design |
| NFC reader matching network | 1 | To design |
---
@@ -134,8 +137,9 @@ The original PCB LEDs are not considered reusable in the current plan.
### NFC
- Use the NFC controller integrated in the nRF52840.
- Integrate the NFC antenna on the PCB if validation confirms this path.
- Do not rely on the nRF52840 NFCT peripheral for passive badge UID reading.
- Select a dedicated NFC reader circuit for badge unlock.
- Integrate and tune the NFC reader antenna on the production PCB.
---
@@ -143,7 +147,8 @@ The original PCB LEDs are not considered reusable in the current plan.
High priority:
- NFC antenna design.
- NFC reader IC selection.
- NFC reader antenna design.
- High-side lock driver selection.
- Buck converter selection.
- LED selection.
@@ -176,6 +181,6 @@ Low priority:
- Opening validation through `COM/NC` selected.
- Lock command through a positive pulse on `SIG` selected.
- Production keypad planned as a 2x6 physical layout on a custom matrix PCB.
- nRF52840 integrated NFC controller selected as the preferred path.
- nRF52840 integrated NFCT identified as tag-side NFC-A hardware, not the passive badge reader path.
- Active buzzer selected and validated through a transistor driver.
- XIAO power through a 12 V to 5 V buck converter selected.
+7 -3
View File
@@ -24,9 +24,13 @@ Features:
---
## NFC Reader
## NFC
The nRF52840 integrated NFC controller is the preferred design path.
The nRF52840 integrated NFC peripheral is NFCT hardware. It supports the tag-side NFC-A role and requires an NFC antenna on `NFC1/P0.09` and `NFC2/P0.10`.
It is not a standalone active NFC reader for passive badges.
Credential badge reading therefore requires a dedicated NFC reader circuit on the production PCB.
Functions:
@@ -34,7 +38,7 @@ Functions:
- Badge validation.
- Unlock request trigger.
The antenna and matching network still need to be designed and validated.
The reader IC, antenna, and matching network still need to be selected, designed, and validated.
---
+1 -1
View File
@@ -37,7 +37,7 @@ Seeed Studio XIAO BLE nRF52840
These signals still need to be assigned after hardware validation:
- Production keypad matrix.
- NFC antenna and matching network.
- Dedicated NFC reader interface, antenna, and matching network.
- Battery voltage measurement.
- External status LEDs.
- Additional expansion signals.