Skip to content
Snippets Groups Projects
Commit e7ed21cc authored by Grzegorz Gwóźdź's avatar Grzegorz Gwóźdź
Browse files

Initial version of rewriting doorlock to C++


Signed-off-by: default avatarGrzegorz Gwozdz <grzegorz.gwozdz@huawei.com>
parent 76036311
No related branches found
No related tags found
No related merge requests found
......@@ -2,9 +2,13 @@
# SPDX-FileCopyrightText: Huawei Inc.
# SPDX-License-Identifier: Apache-2.0
# Bernhard Rosenkraenzer <bernhard.rosenkraenzer.ext@huawei.com>
# Grzegorz Gwozdz <grzegorz.gwozdz@huawei.com>
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
cmake_minimum_required(VERSION 3.16.5)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(doorlock)
project(doorlock LANGUAGES CXX)
target_sources(app PRIVATE src/main.c src/led.c src/kbd.c src/lock_solenoid.c src/lock_rotating.c src/debugconsole.c src/storage.c)
target_sources(app PRIVATE src/solenoid_doorlock.cpp src/rotating_doorlock.cpp src/led.cpp src/led_doorlock.cpp src/main.cpp src/led_rot_doorlock.cpp)
......@@ -100,17 +100,8 @@
kbd6 = &kbd6;
};
chosen {
zephyr,console = &cdc_acm_uart0;
};
};
/* This is for compatibility with Zephyr 2.6.
Remove the next section once we require 2.7. */
zephyr_udc0: &usbd {
compatible = "nordic,nrf-usbd";
status = "okay";
};
&zephyr_udc0 {
cdc_acm_uart0: cdc_acm_uart0 {
......
......@@ -8,11 +8,11 @@ CONFIG_MPU_ALLOW_FLASH_WRITE=y
CONFIG_PRINTK=y
CONFIG_HEAP_MEM_POOL_SIZE=256
CONFIG_ASSERT=y
CONFIG_EXCEPTIONS=y
CONFIG_LOG=y
# For debugging
CONFIG_USB_DEVICE_STACK=y
CONFIG_USB_DEVICE_PRODUCT="Doorlock debugging console"
CONFIG_SERIAL=y
CONFIG_UART_LINE_CTRL=y
CONFIG_UART_CONSOLE=y
CONFIG_USB_CDC_ACM=y
CONFIG_CPLUSPLUS=y
CONFIG_LIB_CPLUSPLUS=y
CONFIG_STD_CPP17=y
CONFIG_NEWLIB_LIBC=y
CONFIG_NEWLIB_LIBC_NANO=n
......@@ -21,3 +21,4 @@ static inline int gpio_pin_set_dt(const struct gpio_dt_spec *spec, int value)
return gpio_pin_set(spec->port, spec->pin, value);
}
#endif
/* Copyright (C) 2021 Huawei Inc.
* SPDX-FileCopyrightText: Huawei Inc.
* SPDX-License-Identifier: Apache-2.0
* Bernhard Rosenkraenzer <bernhard.rosenkraenzer.ext@huawei.com>
*/
#include "debugconsole.h"
int debugconsole_init() {
const struct device *dev = device_get_binding(DT_LABEL(DT_CHOSEN(zephyr_console))); // Once we drop support for < 2.7: DEVICE_DT_GET(DT_CHOSEN(zephyr_console));
uint32_t dtr = 0;
uint32_t retries = 0;
if (usb_enable(NULL)) {
return 1;
}
/* Poll if the DTR flag was set
* Time out after 2 seconds -- we might be
* connected to a power supply only
*/
while (!dtr && (retries++ < 20)) {
uart_line_ctrl_get(dev, UART_LINE_CTRL_DTR, &dtr);
/* Give CPU resources to low priority threads. */
k_sleep(K_MSEC(100));
}
return !dtr;
}
/* Copyright (C) 2021 Huawei Inc.
* SPDX-FileCopyrightText: Huawei Inc.
* SPDX-License-Identifier: Apache-2.0
* Bernhard Rosenkraenzer <bernhard.rosenkraenzer.ext@huawei.com>
* Grzegorz Gwozdz <grzegorz.gwozdz@huawei.com>
*/
#ifndef DOORLOCK_HPP
#define DOORLOCK_HPP
#include <drivers/gpio.h>
#include <sys/printk.h>
class Doorlock
{
public:
/**
* @brief Unlock the doorlock
*/
virtual void unlock() = 0;
/**
* @brief Locking the doorlocklock
*/
virtual void lock() = 0;
};
#endif
/* Copyright (C) 2021 Huawei Inc.
* SPDX-FileCopyrightText: Huawei Inc.
* SPDX-License-Identifier: Apache-2.0
* Bernhard Rosenkraenzer <bernhard.rosenkraenzer.ext@huawei.com>
*/
#include "kbd.h"
#include "led.h"
#include "compat.h"
#include <drivers/gpio.h>
#include <sys/printk.h>
#include <string.h>
static const struct gpio_dt_spec kbd[7] = {
GPIO_DT_SPEC_GET_OR(DT_ALIAS(kbd0), gpios, {0}),
GPIO_DT_SPEC_GET_OR(DT_ALIAS(kbd1), gpios, {0}),
GPIO_DT_SPEC_GET_OR(DT_ALIAS(kbd2), gpios, {0}),
GPIO_DT_SPEC_GET_OR(DT_ALIAS(kbd3), gpios, {0}),
GPIO_DT_SPEC_GET_OR(DT_ALIAS(kbd4), gpios, {0}),
GPIO_DT_SPEC_GET_OR(DT_ALIAS(kbd5), gpios, {0}),
GPIO_DT_SPEC_GET_OR(DT_ALIAS(kbd6), gpios, {0})
};
static const int col_pins[3] = { 6, 2, 1 };
static const int row_pins[4] = { 5, 0, 4, 3 };
static const char keys[4][3] = {
{ '1', '2', '3' },
{ '4', '5', '6' },
{ '7', '8', '9' },
{ '*', '0', '#' }
};
static char pressedKeys[13];
int kbd_init() {
for(int i=0; i<7; i++)
gpio_pin_configure_dt(&kbd[i], GPIO_INPUT | GPIO_PULL_UP);
return 0;
}
char *kbd_scanKeys() {
memset(pressedKeys, 0, 13);
for(int i=0; i<7; i++)
gpio_pin_configure_dt(&kbd[i], GPIO_INPUT | GPIO_PULL_UP);
for(int row=0; row<4; row++) {
gpio_pin_configure_dt(&kbd[row_pins[row]], GPIO_OUTPUT);
gpio_pin_set_dt(&kbd[row_pins[row]], 0);
for(int col=0; col<3; col++) {
if(!gpio_pin_get_dt(&kbd[col_pins[col]]))
pressedKeys[strlen(pressedKeys)] = keys[row][col];
}
gpio_pin_configure_dt(&kbd[row_pins[row]], GPIO_INPUT | GPIO_PULL_UP);
}
return pressedKeys;
}
void kbd_wait_for_release() {
while(kbd_scanKeys()[0] != 0)
k_msleep(100);
}
void kbd_wait_for_key_release(char key) {
while(strchr(kbd_scanKeys(), key))
k_msleep(100);
}
char *kbd_get(int timeout) {
char *ret = k_malloc(13);
memset(ret, 0, 13);
char previous[13];
*previous=0;
while(1) {
char *keys = kbd_scanKeys();
if(keys && *keys) {
if(!*ret) {
strcpy(ret, keys);
} else {
for(int i=0; i<strlen(keys); i++) {
if(!strchr(ret, keys[i]))
ret[strlen(ret)]=keys[i];
}
}
strcpy(previous, keys);
} else if(ret[0]) {
return ret;
}
k_msleep(100);
if(timeout) {
timeout -= 100;
if(timeout <= 0) {
k_free(ret);
return NULL;
}
}
}
}
/* Copyright (C) 2021 Huawei Inc.
* SPDX-FileCopyrightText: Huawei Inc.
* SPDX-License-Identifier: Apache-2.0
* Bernhard Rosenkraenzer <bernhard.rosenkraenzer.ext@huawei.com>
*/
#pragma once
/**
* Initialize the keyboard
*/
int kbd_init();
/**
* scan pressed keys
* @return all currently pressed keys
*/
char *kbd_scanKeys();
/**
* wait until all keys are released
*/
void kbd_wait_for_release();
/**
* wait until a specific key is released
* @param key key to wait for
*/
void kbd_wait_for_key_release(char key);
/**
* Get a key sequence from the keyboard.
* A key sequence is considered complete when at least
* one key has been pressed and all keys have been
* released.
* e.g. just pressing 1 will result in "1".
* Pressing and holding 1, then pressing 2 and 3
* and releasing everything will result in "123".
* Every possible key is counted only once, so
* pressing and holding 1 while pressing 2324
* will result in 1234, not 12324.
* @param timeout timeout in milliseconds (0: no timeout)
* @return key sequence or NULL on timeout. Has to be freed with k_free.
*/
char *kbd_get(int timeout);
/* Copyright (C) 2021 Huawei Inc.
* SPDX-FileCopyrightText: Huawei Inc.
* SPDX-License-Identifier: Apache-2.0
* Bernhard Rosenkraenzer <bernhard.rosenkraenzer.ext@huawei.com>
*/
#include "led.h"
#include "compat.h"
#include <zephyr.h>
#include <drivers/gpio.h>
#include <sys/printk.h>
#include <string.h>
#define LED0_NODE DT_ALIAS(led0)
#if DT_NODE_HAS_STATUS(LED0_NODE, okay)
static struct gpio_dt_spec led0 = GPIO_DT_SPEC_GET_OR(LED0_NODE, gpios, {0});
#else
#warning led0 not defined in devicetree, LED commands will be ignored
static struct gpio_dt_spec led0 = { NULL, 0, 0 };
#endif
enum led_status __led_status;
K_FIFO_DEFINE(led_blink_thread_control);
struct led_blink_thread_msg_t {
void *fifo_reserved;
int frequency;
};
static void led_blink_thread_handler(void *p1, void *p2, void *p3) {
while(1) {
struct led_blink_thread_msg_t *data = (struct led_blink_thread_msg_t*)k_fifo_get(&led_blink_thread_control, K_FOREVER);
int frequency = data->frequency;
k_free(data);
while(frequency) {
led_toggle();
data = k_fifo_get(&led_blink_thread_control, K_MSEC(frequency));
if(data) {
frequency = data->frequency;
k_free(data);
}
}
led_off();
}
}
K_THREAD_DEFINE(led_blink_thread, 512, led_blink_thread_handler, NULL, NULL, NULL, 7, 0, 0);
int led_init() {
if(led0.port && !device_is_ready(led0.port)) {
printk("LED led0 not ready, LED commands will be ignored\n");
led0.port = NULL;
}
if(led0.port) {
gpio_pin_configure_dt(&led0, GPIO_OUTPUT);
gpio_pin_set_dt(&led0, 1);
return 0;
} else {
return ENODEV;
}
}
void led_on() {
gpio_pin_set_dt(&led0, 0);
__led_status |= 1;
}
void led_off() {
gpio_pin_set_dt(&led0, 1);
__led_status &= ~1;
}
void led_toggle() {
gpio_pin_set_dt(&led0, __led_status&1);
__led_status ^= 1;
}
void led_blink() {
led_toggle();
k_msleep(500);
led_toggle();
k_msleep(500);
}
void led_start_blinking(int frequency) {
if(!frequency && !(__led_status&BLINKING))
return;
struct led_blink_thread_msg_t msg = { .frequency = frequency };
const size_t size = sizeof(struct led_blink_thread_msg_t);
char *mem = k_malloc(size);
memcpy(mem, &msg, size);
k_fifo_put(&led_blink_thread_control, mem);
if(frequency)
__led_status |= BLINKING;
else
__led_status &= ~BLINKING;
}
void led_stop_blinking() {
led_start_blinking(0);
}
enum led_status led_status() {
return __led_status;
}
/* Copyright (C) 2021 Huawei Inc.
* SPDX-FileCopyrightText: Huawei Inc.
* SPDX-License-Identifier: Apache-2.0
* Bernhard Rosenkraenzer <bernhard.rosenkraenzer.ext@huawei.com>
* Grzegorz Gwozdz <grzegorz.gwozdz@huawei.com>
*/
#include "led.hpp"
#include "compat.h"
#include <drivers/gpio.h>
#include <string.h>
#include <sys/printk.h>
#include <zephyr.h>
#define LED0_NODE DT_ALIAS(led0)
#if DT_NODE_HAS_STATUS(LED0_NODE, okay)
static struct gpio_dt_spec led0 = GPIO_DT_SPEC_GET_OR(LED0_NODE, gpios, {0});
#else
#warning led0 not defined in devicetree, LED commands will be ignored
static struct gpio_dt_spec led0 = {NULL, 0, 0};
#endif
int __led_status = 0x00;
K_FIFO_DEFINE(led_blink_thread_control);
struct led_blink_thread_msg_t
{
void *fifo_reserved;
int frequency;
};
namespace {
void led_blink_thread_handler(void *p1, void *p2, void *p3)
{
while (1) {
struct led_blink_thread_msg_t *data =
(struct led_blink_thread_msg_t *)k_fifo_get(&led_blink_thread_control,
K_FOREVER);
int frequency = data->frequency;
k_free(data);
while (frequency) {
led_toggle();
data = (led_blink_thread_msg_t *)k_fifo_get(&led_blink_thread_control,
K_MSEC(frequency));
if (data)
{
frequency = data->frequency;
k_free(data);
}
}
led_off();
}
}
} /* namespace */
K_THREAD_DEFINE(led_blink_thread, 512, led_blink_thread_handler, NULL, NULL,
NULL, 7, 0, 0);
void led_init()
{
if (led0.port && !device_is_ready(led0.port)) {
printk("LED led0 not ready, LED commands will be ignored\n");
led0.port = NULL;
}
if (led0.port) {
gpio_pin_configure_dt(&led0, GPIO_OUTPUT);
gpio_pin_set_dt(&led0, 1);
}
else {
throw(ENODEV);
}
}
void led_on()
{
gpio_pin_set_dt(&led0, 0);
__led_status |= 1;
}
void led_off()
{
gpio_pin_set_dt(&led0, 1);
__led_status &= ~1;
}
void led_toggle()
{
gpio_pin_set_dt(&led0, __led_status & 1);
__led_status ^= 1;
}
void led_blink()
{
printk("%d ", __led_status);
led_toggle();
k_msleep(500);
led_toggle();
k_msleep(500);
}
void led_start_blinking(int frequency)
{
if (!frequency && !(__led_status & int(led_status::BLINKING)))
return;
struct led_blink_thread_msg_t msg = {.frequency = frequency};
const size_t size = sizeof(struct led_blink_thread_msg_t);
char *mem = (char *)k_malloc(size);
memcpy(mem, &msg, size);
k_fifo_put(&led_blink_thread_control, mem);
if (frequency)
__led_status |= int(led_status::BLINKING);
else
__led_status &= ~int(led_status::BLINKING);
}
void led_stop_blinking()
{
led_start_blinking(0);
}
int led_status()
{
return __led_status;
}
......@@ -6,42 +6,51 @@
#pragma once
enum led_status {
enum class led_status
{
OFF = 0x00,
ON = 0x01,
BLINKING = 0x02
};
/**
* Initialize the LED
* @brief Initialize the LED
*/
int led_init();
void led_init();
/**
* Turn the LED on
* @brief Turn the LED on
*/
void led_on();
/**
* Turn the LED off
* @brief Turn the LED off
*/
void led_off();
/**
* Toggle the LED
* @brief Toggle the LED
*/
void led_toggle();
/**
* Blink the LED once (toggle for 1 second, then toggle back)
* @brief Blink the LED once (toggle for 1 second, then toggle back)
*/
void led_blink();
/**
* Start blinking the LED
* @brief Start blinking the LED
* @param frequency frequency in milliseconds
*/
void led_start_blinking(int frequency);
/**
* Stop blinking the LED
* @brief Stop blinking the LED
*/
void led_stop_blinking();
/**
* Get the status of the LED
* @brief Get the status of the LED
* @return Status of the LED
*/
enum led_status led_status();
int led_status();
/* Copyright (C) 2021 Huawei Inc.
* SPDX-FileCopyrightText: Huawei Inc.
* SPDX-License-Identifier: Apache-2.0
* Bernhard Rosenkraenzer <bernhard.rosenkraenzer.ext@huawei.com>
* Grzegorz Gwozdz <grzegorz.gwozdz@huawei.com>
*/
#include "led_doorlock.hpp"
#include "doorlock.hpp"
#include "led.hpp"
/**
* @brief Lock Led implementation
* It's not even a real doorlock, its sole purpose
* is to test the class implementation introduced in the new version
*/
LedDoorlock::LedDoorlock() : Doorlock()
{
led_init();
}
void LedDoorlock::unlock()
{
led_off();
}
void LedDoorlock::lock()
{
led_on();
}
......@@ -2,17 +2,22 @@
* SPDX-FileCopyrightText: Huawei Inc.
* SPDX-License-Identifier: Apache-2.0
* Bernhard Rosenkraenzer <bernhard.rosenkraenzer.ext@huawei.com>
* Grzegorz Gwozdz <grzegorz.gwozdz@huawei.com>
*/
#pragma once
#ifndef NDEBUG
#include <usb/usb_device.h>
#include <drivers/uart.h>
#ifndef LED_DOORLOCK_HPP
#define LED_DOORLOCK_HPP
BUILD_ASSERT(DT_NODE_HAS_COMPAT(DT_CHOSEN(zephyr_console), zephyr_cdc_acm_uart),
"Console device is not ACM CDC UART device");
#include "doorlock.hpp"
class LedDoorlock : public Doorlock
{
public:
LedDoorlock();
void unlock();
void lock();
private:
const struct device *Pin0, *Pin1;
};
int debugconsole_init();
#else
static int debugconsole_init() { }
#endif
/* Copyright (C) 2021 Huawei Inc.
* SPDX-FileCopyrightText: Huawei Inc.
* SPDX-License-Identifier: Apache-2.0
* Bernhard Rosenkraenzer <bernhard.rosenkraenzer.ext@huawei.com>
* Grzegorz Gwozdz <grzegorz.gwozdz@huawei.com>
*/
#include "led_rot_doorlock.hpp"
#include "doorlock.hpp"
#include "led.hpp"
#include <zephyr/logging/log.h>
#define DOORLOCK0_NODE DT_ALIAS(doorlock0)
#if DT_NODE_HAS_STATUS(DOORLOCK0_NODE, okay)
#define DOORLOCK0 DT_GPIO_LABEL(DOORLOCK0_NODE, gpios)
#define PIN0 DT_GPIO_PIN(DOORLOCK0_NODE, gpios)
#define FLAGS0 DT_GPIO_FLAGS(DOORLOCK0_NODE, gpios)
#else
#error "Unsupported board: doorlock0 devicetree alias is not defined"
#endif
#define DOORLOCK1_NODE DT_ALIAS(doorlock1)
#if DT_NODE_HAS_STATUS(DOORLOCK1_NODE, okay)
#define DOORLOCK1 DT_GPIO_LABEL(DOORLOCK1_NODE, gpios)
#define PIN1 DT_GPIO_PIN(DOORLOCK1_NODE, gpios)
#define FLAGS1 DT_GPIO_FLAGS(DOORLOCK1_NODE, gpios)
#else
#error "Unsupported board: doorlock1 devicetree alias is not defined"
#endif
#define CONFIG_LED_LOG_LEVEL 4
LOG_MODULE_DECLARE(LedRotatingDoorlock, CONFIG_LED_LOG_LEVEL);
/**
* @brief Lock Rotating Led implementation
* It's not even a real doorlock, its sole purpose
* is to test the class implementation introduced in the new version
* This also tests CONTAINET_OF functionalities implemented
* in RotatingDoorlock class
*
* Right now, it prints in the console besides led lighting
*
*/
void lock_stop_led_rotating_timer_handler(k_timer *timer_id)
{
LOG_DBG("Got to this timer_handler...\n");
LedRotatingDoorlock::timer_wrapper *wrapper =
CONTAINER_OF(timer_id, struct LedRotatingDoorlock::timer_wrapper, timer);
wrapper->lock->lock_rotating_stop();
}
LedRotatingDoorlock::LedRotatingDoorlock() : Doorlock(), wrapper(this)
{
led_init();
LOG_INF("Initialized\n");
k_timer_init(&wrapper.timer, lock_stop_led_rotating_timer_handler, NULL);
}
void LedRotatingDoorlock::lock_rotating_rotate_clockwise()
{
led_on();
LOG_INF("Locking...\n");
}
void LedRotatingDoorlock::lock_rotating_rotate_counterclockwise()
{
led_off();
LOG_INF("Unlocking...\n");
}
void LedRotatingDoorlock::lock_rotating_stop()
{
LOG_DBG("Got to lock_rotating_stop!\n");
// No point in leaving an auto-stop running if we've already stopped it
k_timer_stop(&wrapper.timer);
}
void LedRotatingDoorlock::unlock()
{
lock_rotating_rotate_counterclockwise();
k_timer_start(&wrapper.timer, K_SECONDS(1), K_NO_WAIT);
}
void LedRotatingDoorlock::lock()
{
lock_rotating_rotate_clockwise();
// It takes roughly 13 seconds to go from fully open to fully closed
// but for the testing purpose we are waiting only 1 second
k_timer_start(&wrapper.timer, K_SECONDS(1), K_NO_WAIT);
}
void LedRotatingDoorlock::unlock_lock(int time)
{
lock();
//we have to wait for at least a second
if (time < 1)
time = 1;
k_timer_start(&wrapper.timer, K_SECONDS(time), K_NO_WAIT);
unlock();
}
/* Copyright (C) 2021 Huawei Inc.
* SPDX-FileCopyrightText: Huawei Inc.
* SPDX-License-Identifier: Apache-2.0
* Bernhard Rosenkraenzer <bernhard.rosenkraenzer.ext@huawei.com>
* Grzegorz Gwozdz <grzegorz.gwozdz@huawei.com>
*/
#ifndef LED_ROT_DOORLOCK_HPP
#define LED_ROT_DOORLOCK_HPP
#include "doorlock.hpp"
class LedRotatingDoorlock : public Doorlock
{
public:
LedRotatingDoorlock();
void unlock();
/**
* @brief Unlock, then lock the lock
* It is usually a good idea to use unlock_lock
* rather than unlock because keeping the doorlock in
* its unlocked state may drive up power consumption (the lock
* is essentially pulled in by a strong electric magnet).
* @param time Time in seconds to keep unlocked
*/
void lock();
void unlock_lock(int time);
private:
struct timer_wrapper
{
timer_wrapper(LedRotatingDoorlock * new_lock) :
lock(new_lock) { };
LedRotatingDoorlock *lock;
k_timer timer;
} wrapper;
/**
* @brief Start rotating clockwise (locking)
*/
void lock_rotating_rotate_clockwise();
/**
* @brief Start rotating counterclockwise (unlocking)
*/
void lock_rotating_rotate_counterclockwise();
/**
* @brief Stop the motor
*/
void lock_rotating_stop();
friend void lock_stop_led_rotating_timer_handler(k_timer *timer_id);
};
#endif
/* Copyright (C) 2021 Huawei Inc.
* SPDX-FileCopyrightText: Huawei Inc.
* SPDX-License-Identifier: Apache-2.0
* Bernhard Rosenkraenzer <bernhard.rosenkraenzer.ext@huawei.com>
*/
#include "lock_rotating.h"
#include <drivers/gpio.h>
#include <sys/printk.h>
#define DOORLOCK0_NODE DT_ALIAS(doorlock0)
#if DT_NODE_HAS_STATUS(DOORLOCK0_NODE, okay)
#define DOORLOCK0 DT_GPIO_LABEL(DOORLOCK0_NODE, gpios)
#define PIN0 DT_GPIO_PIN(DOORLOCK0_NODE, gpios)
#define FLAGS0 DT_GPIO_FLAGS(DOORLOCK0_NODE, gpios)
#else
#error "Unsupported board: doorlock0 devicetree alias is not defined"
#endif
#define DOORLOCK1_NODE DT_ALIAS(doorlock1)
#if DT_NODE_HAS_STATUS(DOORLOCK1_NODE, okay)
#define DOORLOCK1 DT_GPIO_LABEL(DOORLOCK1_NODE, gpios)
#define PIN1 DT_GPIO_PIN(DOORLOCK1_NODE, gpios)
#define FLAGS1 DT_GPIO_FLAGS(DOORLOCK1_NODE, gpios)
#else
#error "Unsupported board: doorlock1 devicetree alias is not defined"
#endif
static const struct device *motorPin0 = NULL, *motorPin1 = NULL;
void lock_stop_rotating_timer_handler(struct k_timer *timer) {
lock_rotating_stop();
}
K_TIMER_DEFINE(lock_stop_rotating_timer, lock_stop_rotating_timer_handler, NULL);
int lock_rotating_init() {
motorPin0 = device_get_binding(DOORLOCK0);
if(!motorPin0) {
printk("Can't get devicetree entry for doorlock0\n");
return ENODEV;
}
motorPin1 = device_get_binding(DOORLOCK1);
if(!motorPin1) {
printk("Can't get devicetree entry for doorlock0\n");
return ENODEV;
}
if(gpio_pin_configure(motorPin0, PIN0, GPIO_OUTPUT_ACTIVE | FLAGS0) < 0) {
printk("Can't configure motor pin 0\n");
return ENODEV;
}
if(gpio_pin_configure(motorPin1, PIN1, GPIO_OUTPUT_ACTIVE | FLAGS1) < 0) {
printk("Can't configure motor pin 1\n");
return ENODEV;
}
return 0;
}
void lock_rotating_rotate_clockwise() {
gpio_pin_configure(motorPin1, PIN1, FLAGS1);
gpio_pin_configure(motorPin0, PIN0, FLAGS0 | GPIO_OUTPUT_ACTIVE | GPIO_ACTIVE_HIGH);
}
void lock_rotating_rotate_counterclockwise() {
gpio_pin_configure(motorPin0, PIN0, FLAGS0);
gpio_pin_configure(motorPin1, PIN1, FLAGS1 | GPIO_OUTPUT_ACTIVE | GPIO_ACTIVE_HIGH);
}
void lock_rotating_stop() {
k_timer_stop(&lock_stop_rotating_timer); // No point in leaving an auto-stop running if we've already stopped it
gpio_pin_set(motorPin0, PIN0, 0);
gpio_pin_set(motorPin1, PIN1, 0);
}
void lock_rotating_unlock() {
lock_rotating_rotate_counterclockwise();
k_timer_start(&lock_stop_rotating_timer, K_SECONDS(13), K_NO_WAIT); // It takes roughly 13 seconds to go from fully closed to fully open
}
void lock_rotating_lock() {
lock_rotating_rotate_clockwise();
k_timer_start(&lock_stop_rotating_timer, K_SECONDS(13), K_NO_WAIT); // It takes roughly 13 seconds to go from fully open to fully closed
}
/* Copyright (C) 2021 Huawei Inc.
* SPDX-FileCopyrightText: Huawei Inc.
* SPDX-License-Identifier: Apache-2.0
* Bernhard Rosenkraenzer <bernhard.rosenkraenzer.ext@huawei.com>
*/
#pragma once
/**
* Initialize the rotating motor lock
*/
int lock_rotating_init();
/**
* Start rotating clockwise (locking)
*/
void lock_rotating_rotate_clockwise();
/**
* Start rotating counterclockwise (unlocking)
*/
void lock_rotating_rotate_counterclockwise();
/**
* Stop the motor
*/
void lock_rotating_stop();
/**
* Unlock fully (rotate until unlock position is reached)
*/
void lock_rotating_unlock();
/**
* Lock fully (rotate until unlock position is reached)
*/
void lock_rotating_lock();
/* Copyright (C) 2021 Huawei Inc.
* SPDX-FileCopyrightText: Huawei Inc.
* SPDX-License-Identifier: Apache-2.0
* Bernhard Rosenkraenzer <bernhard.rosenkraenzer.ext@huawei.com>
*/
#include "lock_solenoid.h"
#include <drivers/gpio.h>
#include <sys/printk.h>
#define DOORLOCK0_NODE DT_ALIAS(doorlock0)
#if DT_NODE_HAS_STATUS(DOORLOCK0_NODE, okay)
#define DOORLOCK0 DT_GPIO_LABEL(DOORLOCK0_NODE, gpios)
#define PIN0 DT_GPIO_PIN(DOORLOCK0_NODE, gpios)
#define FLAGS0 DT_GPIO_FLAGS(DOORLOCK0_NODE, gpios)
#else
#error "Unsupported board: doorlock0 devicetree alias is not defined"
#endif
#define DOORLOCK1_NODE DT_ALIAS(doorlock1)
#if DT_NODE_HAS_STATUS(DOORLOCK1_NODE, okay)
#define DOORLOCK1 DT_GPIO_LABEL(DOORLOCK1_NODE, gpios)
#define PIN1 DT_GPIO_PIN(DOORLOCK1_NODE, gpios)
#define FLAGS1 DT_GPIO_FLAGS(DOORLOCK1_NODE, gpios)
#else
#error "Unsupported board: doorlock1 devicetree alias is not defined"
#endif
static const struct device *solenoidPin0 = NULL, *solenoidPin1 = NULL;
int lock_solenoid_init() {
solenoidPin0 = device_get_binding(DOORLOCK0);
if(!solenoidPin0) {
printk("Can't get devicetree entry for doorlock0\n");
return ENODEV;
}
solenoidPin1 = device_get_binding(DOORLOCK1);
if(!solenoidPin1) {
printk("Can't get devicetree entry for doorlock0\n");
return ENODEV;
}
if(gpio_pin_configure(solenoidPin0, PIN0, GPIO_OUTPUT_ACTIVE | FLAGS0) < 0) {
printk("Can't configure solenoid pin 0\n");
return ENODEV;
}
if(gpio_pin_configure(solenoidPin1, PIN1, GPIO_OUTPUT_ACTIVE | FLAGS1) < 0) {
printk("Can't configure solenoid pin 1\n");
return ENODEV;
}
return 0;
}
void lock_solenoid_unlock() {
gpio_pin_configure(solenoidPin0, PIN0, FLAGS0 | GPIO_OUTPUT_ACTIVE | GPIO_ACTIVE_LOW);
gpio_pin_configure(solenoidPin1, PIN1, FLAGS1 | GPIO_OUTPUT_ACTIVE | GPIO_ACTIVE_HIGH);
}
void lock_solenoid_lock() {
gpio_pin_configure(solenoidPin0, PIN0, FLAGS0);
gpio_pin_configure(solenoidPin1, PIN1, FLAGS1);
}
void lock_solenoid_unlock_lock(int time) {
lock_solenoid_unlock();
k_msleep(time);
lock_solenoid_lock();
}
/* Copyright (C) 2021 Huawei Inc.
* SPDX-FileCopyrightText: Huawei Inc.
* SPDX-License-Identifier: Apache-2.0
* Bernhard Rosenkraenzer <bernhard.rosenkraenzer.ext@huawei.com>
*/
#pragma once
/**
* Initialize the lock solenoid
*/
int lock_solenoid_init();
/**
* Unlock the solenoid
*/
void lock_solenoid_unlock();
/**
* Lock the solenoid
*/
void lock_solenoid_lock();
/**
* Unlock, then lock the solenoid
* It is usually a good idea to use lock_solenoid_unlock_lock
* rather than lock_solenoid_unlock because keeping the solenoid
* in its unlocked state drives up power consumption (the lock
* is essentially pulled in by a strong electric magnet).
* @param time Time in milliseconds to keep unlocked
*/
void lock_solenoid_unlock_lock(int time);
/* Copyright (C) 2021 Huawei Inc.
* SPDX-FileCopyrightText: Huawei Inc.
* SPDX-License-Identifier: Apache-2.0
* Bernhard Rosenkraenzer <bernhard.rosenkraenzer.ext@huawei.com>
*/
// Use the rotating motor lock (if not set, the solenoid will be used)
// #define LOCKTYPE_ROTATING 1
// Allow changing the pin by pressing *# within
// PIN_CHANGE_TIMEOUT milliseconds of a successful unlock
#define PIN_CHANGE_TIMEOUT 10000
// Automatically re-lock RELOCK_TIMEOUT milliseconds after
// a successful unlock (if 0, the per-lock type default
// will be used -- rotating motor should usually have
// a much longer timeout. If -1, this functionality is disabled)
#define RELOCK_TIMEOUT 0
// Maximum size of a pin
#define MAX_PINSIZE 128
#include <zephyr.h>
#include <sys/printk.h>
#include <string.h>
#include "debugconsole.h"
#include "led.h"
#include "kbd.h"
#ifdef LOCKTYPE_ROTATING
#include "lock_rotating.h"
#define lock_init lock_rotating_init
#define lock_unlock lock_rotating_unlock
#define lock_lock lock_rotating_lock
#if RELOCK_TIMEOUT == 0
#undef RELOCK_TIMEOUT
#define RELOCK_TIMEOUT 25000
#endif
#else
#include "lock_solenoid.h"
#define lock_init lock_solenoid_init
#define lock_unlock lock_solenoid_unlock
#define lock_lock lock_solenoid_lock
#if RELOCK_TIMEOUT == 0
#undef RELOCK_TIMEOUT
#define RELOCK_TIMEOUT 4000
#endif
#endif
#include "storage.h"
static void relock(struct k_timer *timer) {
lock_lock();
}
K_TIMER_DEFINE(relock_timer, relock, NULL);
/*
* Read a new pin from the keyboard
*/
char *get_new_pin() {
led_start_blinking(200);
char pin[MAX_PINSIZE];
memset(pin, 0, sizeof(pin));
while(1) {
char *component = kbd_get(0);
if(!component)
continue;
if(component) {
if(!strcmp(component, "*#")) {
if(pin[0]) {
k_free(component);
led_stop_blinking();
char *ret = k_malloc(strlen(pin));
pin[strlen(pin)-1]=0; // strip trailing space
strcpy(ret, pin);
return ret;
}
}
if((strlen(pin) + strlen(component) + 2) > sizeof(pin)) {
led_stop_blinking();
memset(pin, 0, sizeof(pin));
led_blink();
led_blink();
led_blink();
led_start_blinking(200);
} else {
strcat(pin, component);
strcat(pin, " ");
}
k_free(component);
}
}
}
char *set_pin() {
char *pin = get_new_pin();
printk("New pin: ---%s---\n", pin);
nvs_write(&storage_fs, 0, pin, strlen(pin) + 1);
return pin;
}
void main(void)
{
int64_t last_unlock = 0;
int log = 0;
log = (0 == debugconsole_init());
if(log) {
printk("Debugconsole inited\n");
}
led_init();
kbd_init();
lock_init();
storage_init();
char pin[MAX_PINSIZE];
int ret = nvs_read(&storage_fs, 0, pin, sizeof(pin));
if(ret>0) {
if(log) {
printk("Found previous pin: ---%s---\n", pin);
}
} else {
if (log) {
printk("No previous pin\n");
}
char *new_pin = set_pin();
strcpy(pin, new_pin);
k_free(new_pin);
if (log) {
printk("Starting with new pin: ---%s---\n", pin);
}
}
char input[MAX_PINSIZE];
memset(input, 0, sizeof(input));
led_blink();
while(1) {
if (log) {
printk("Ready and waiting for input\n");
}
led_off();
led_on();
k_msleep(1);
led_off();
char *component = kbd_get(0);
if(!component)
continue;
if(!strcmp(component, "*#") && last_unlock && ((k_uptime_get() - last_unlock) < PIN_CHANGE_TIMEOUT)) {
if (log) {
printk("PIN change requested\n");
}
char *new_pin = set_pin();
strcpy(pin, new_pin);
k_free(new_pin);
if (log) {
printk("Pin changed to: ---%s---\n", pin);
}
continue;
}
if((strlen(input) + strlen(component) + 2) > sizeof(input)) {
memset(input, 0, sizeof(input));
} else {
strcat(input, component);
if(!strcmp(input, pin)) {
led_on();
if (log) {
printk("Correct pin received! unlocking!\n");
}
lock_unlock();
if (log) {
printk("Unlocked, proceeding\n");
}
led_off();
last_unlock = k_uptime_get();
memset(input, 0, sizeof(input));
k_timer_start(&relock_timer, K_MSEC(RELOCK_TIMEOUT), K_NO_WAIT);
} else {
strcat(input, " ");
if(strncmp(input, pin, strlen(input)))
memset(input, 0, sizeof(input));
}
}
k_free(component);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment