feat(firmware): add open detector

This commit is contained in:
2026-07-10 19:28:40 +02:00
parent 8892e0bfc4
commit bebe0c6b2c
10 changed files with 179 additions and 10 deletions
-1
View File
@@ -66,5 +66,4 @@ _autosave-*
# ----------------------------
# Divers
# ----------------------------
archives/
tools/
View File
+1
View File
@@ -12,6 +12,7 @@ target_sources(app PRIVATE
src/main.c
src/led.c
src/buzzer.c
src/lock_state.c
src/gpio_expander.c
src/keypad.c
)
+10
View File
@@ -30,4 +30,14 @@
#define BUZZER_GPIO_PIN 2
#define BUZZER_GPIO_FLAGS GPIO_ACTIVE_HIGH
/* Lock state feedback */
#define LOCK_STATE_NC_GPIO_NODE DT_NODELABEL(gpio1)
#define LOCK_STATE_NC_GPIO_PIN 12
#define LOCK_STATE_NC_GPIO_FLAGS GPIO_ACTIVE_LOW
#define LOCK_STATE_COM_GPIO_NODE DT_NODELABEL(gpio1)
#define LOCK_STATE_COM_GPIO_PIN 13
#define LOCK_STATE_COM_GPIO_FLAGS GPIO_ACTIVE_HIGH
#endif /* BOARD_CONFIG_H */
+54
View File
@@ -0,0 +1,54 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* OpenParcelBox
* Copyright (c) 2026
*
* Lock state feedback driver.
*/
#include "lock_state.h"
#include "board_config.h"
#include <zephyr/drivers/gpio.h>
/* D7 on the Seeed Studio XIAO nRF52840 is mapped to GPIO1 pin 12. */
static const struct gpio_dt_spec lock_state_nc_gpio = {
.port = DEVICE_DT_GET(LOCK_STATE_NC_GPIO_NODE),
.pin = LOCK_STATE_NC_GPIO_PIN,
.dt_flags = LOCK_STATE_NC_GPIO_FLAGS,
};
/* D8 on the Seeed Studio XIAO nRF52840 is mapped to GPIO1 pin 13. */
static const struct gpio_dt_spec lock_state_com_gpio = {
.port = DEVICE_DT_GET(LOCK_STATE_COM_GPIO_NODE),
.pin = LOCK_STATE_COM_GPIO_PIN,
.dt_flags = LOCK_STATE_COM_GPIO_FLAGS,
};
int lock_state_init(void) {
int ret;
if (!gpio_is_ready_dt(&lock_state_nc_gpio) ||
!gpio_is_ready_dt(&lock_state_com_gpio)) {
return -1;
}
ret = gpio_pin_configure_dt(&lock_state_com_gpio, GPIO_OUTPUT_LOW);
if (ret < 0) {
return ret;
}
return gpio_pin_configure_dt(&lock_state_nc_gpio, GPIO_INPUT | GPIO_PULL_UP);
}
bool lock_state_is_open(void) {
int state = gpio_pin_get_dt(&lock_state_nc_gpio);
if (state < 0) {
return false;
}
return state != 0;
}
+45
View File
@@ -0,0 +1,45 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* OpenParcelBox
* Copyright (c) 2026
*
* Lock state feedback driver.
*/
#ifndef LOCK_STATE_H
#define LOCK_STATE_H
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Initialize the lock state input.
*
* Configures the KR-S79 NC feedback contact input with an internal pull-up and
* drives the COM reference output low.
*
* @retval 0 Success.
* @retval <0 Initialization failed.
*/
int lock_state_init(void);
/**
* @brief Return whether the lock is open.
*
* The KR-S79 COM/NC contact connects D7 to D8 when the latch is open. D8 is
* driven low by the firmware, so the D7 input is active low.
*
* @retval true Lock is open.
* @retval false Lock is closed or the input could not be read.
*/
bool lock_state_is_open(void);
#ifdef __cplusplus
}
#endif
#endif /* LOCK_STATE_H */
+58 -8
View File
@@ -9,6 +9,7 @@
* Current test:
* - RGB LED
* - Buzzer
* - Lock state feedback
* - GPIO Expander
* - 4x4 Keypad
*/
@@ -16,6 +17,7 @@
#include "buzzer.h"
#include "keypad.h"
#include "led.h"
#include "lock_state.h"
#include <zephyr/kernel.h>
@@ -27,6 +29,19 @@
#define MAIN_LOOP_DELAY_MS 20
#define KEY_PRESS_LED_MS 100
#define LOCK_OPEN_BEEP_INTERVAL_MS 2000
/* --------------------------------------------------------------------------
* Private helpers
* -------------------------------------------------------------------------- */
static void set_idle_led(bool lock_open) {
if (lock_open) {
led_set_red();
} else {
led_set_green();
}
}
/* --------------------------------------------------------------------------
* Public API
@@ -34,6 +49,9 @@
int main(void) {
char key;
bool lock_open;
bool previous_lock_open;
int64_t next_lock_open_beep_ms;
if (led_init() < 0) {
return 0;
@@ -50,6 +68,14 @@ int main(void) {
}
}
if (lock_state_init() < 0) {
led_set_magenta();
while (1) {
k_msleep(1000);
}
}
if (keypad_init() < 0) {
led_set_magenta();
@@ -58,17 +84,39 @@ int main(void) {
}
}
led_set_green();
lock_open = lock_state_is_open();
previous_lock_open = lock_open;
next_lock_open_beep_ms = k_uptime_get();
set_idle_led(lock_open);
printf("\n");
printf("========================================\n");
printf("OpenParcelBox Firmware\n");
printf("Hardware Test: RGB LED + Buzzer + Keypad\n");
printf("Hardware Test: RGB LED + Buzzer + Lock State + Keypad\n");
printf("========================================\n");
led_set_green();
set_idle_led(lock_open);
while (1) {
lock_open = lock_state_is_open();
if (lock_open != previous_lock_open) {
set_idle_led(lock_open);
previous_lock_open = lock_open;
if (lock_open) {
printf("Door opened\n");
next_lock_open_beep_ms = k_uptime_get();
} else {
printf("Door closed\n");
}
}
if (lock_open && k_uptime_get() >= next_lock_open_beep_ms) {
buzzer_beep_key();
next_lock_open_beep_ms = k_uptime_get() + LOCK_OPEN_BEEP_INTERVAL_MS;
}
key = keypad_get_key();
@@ -76,14 +124,16 @@ int main(void) {
printf("Key pressed: %c\n", key);
/* keypad_get_key() returns once per press, so holding a key will not beep continuously. */
buzzer_beep_key();
if (!lock_open) {
/* keypad_get_key() returns once per press, so holding a key will not beep continuously. */
buzzer_beep_key();
led_set_blue();
led_set_blue();
k_msleep(KEY_PRESS_LED_MS);
k_msleep(KEY_PRESS_LED_MS);
led_set_green();
led_set_green();
}
}
k_msleep(MAIN_LOOP_DELAY_MS);
+2 -1
View File
@@ -21,6 +21,8 @@ Seeed Studio XIAO BLE nRF52840
| Function | Direction | Pin | Notes |
| --- | --- | --- | --- |
| Active buzzer control | Output | D0 | GPIO signal to transistor driver |
| Lock NC feedback | Input | D7 | KR-S79 NC contact, internal pull-up enabled |
| Lock COM feedback reference | Output | D8 | KR-S79 COM contact, driven low for NC continuity detection |
| PCF8574 I2C SDA | I/O | SDA | Development keypad GPIO expander |
| PCF8574 I2C SCL | Output | SCL | Development keypad GPIO expander |
| RGB LED red | Output | Board LED alias `led0` | On-board validation LED |
@@ -34,7 +36,6 @@ Seeed Studio XIAO BLE nRF52840
These signals still need to be assigned after hardware validation:
- Lock `SIG` command.
- Lock `COM/NC` feedback.
- Production keypad matrix.
- NFC antenna and matching network.
- Battery voltage measurement.
@@ -167,4 +167,6 @@ The Seeed Studio XIAO BLE nRF52840 must:
The `COM/NC` contact changes state as soon as the latch is released. It provides reliable feedback for confirming opening without waiting for a fixed delay.
In the current development wiring, `NC` is connected to XIAO `D7` and `COM` is connected to XIAO `D8`. The firmware drives `D8` low and reads `D7` with an internal pull-up; when `COM/NC` closes, `D7` reads low.
The `COM/NO` contact is not currently used by OpenParcelBox.
@@ -111,6 +111,13 @@ The `COM/NC` contact changes state as soon as the latch leaves the locked positi
This feedback confirms unlocking immediately without waiting for the full mechanism travel.
Current development wiring:
- `NC` is connected to XIAO `D7`.
- `COM` is connected to XIAO `D8`.
- The firmware drives `D8` low and reads `D7` with an internal pull-up.
- When `COM/NC` closes, `D7` reads low.
---
## Sensor