feat(firmware): add nfc logic add doc corrections
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -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`.
|
||||
|
||||
@@ -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
@@ -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.
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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
@@ -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.
|
||||
|
||||
@@ -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
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user