feat(firmware): add open detector
This commit is contained in:
@@ -66,5 +66,4 @@ _autosave-*
|
||||
# ----------------------------
|
||||
# Divers
|
||||
# ----------------------------
|
||||
archives/
|
||||
tools/
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user