Compare commits

..

20 Commits

Author SHA1 Message Date
940fa5b9b1 remove unused library 2020-06-21 10:10:54 +02:00
09dfd6c6f5 README: describe project 2020-06-21 10:08:02 +02:00
a78d45e94b application: add LED animation 2020-06-21 09:59:52 +02:00
284065b62f application: remove lengthy version description 2020-06-21 09:59:25 +02:00
ac9eb9bac9 ws2812b: use push-pull output for noisy cable 2020-06-21 09:54:56 +02:00
4f91856445 ws2812b: only 6 LEDs are used fot this project 2020-06-21 09:54:38 +02:00
26382c9712 usb: increase tx buffer for debugging long messages 2020-06-21 09:44:31 +02:00
367ff5d8b5 README: update flashing over BT details 2020-05-31 23:54:31 +02:00
eff94f9841 global: disable debug to enable watchdog 2020-05-31 23:54:31 +02:00
3ce0eaea91 uart: add one data bit for parity 2020-05-31 23:54:31 +02:00
660d351bcb ld: enforce 128 KiB flash space 2020-05-31 23:54:31 +02:00
972f768512 README: add battery note 2020-05-31 23:54:31 +02:00
ad72c18556 add script to configure HC-05 bluetooth module 2020-05-31 23:54:31 +02:00
af8aca9218 README: document dachtuer project 2020-05-31 23:54:31 +02:00
7d425f6cfb application: commit dachtuer application 2020-05-31 23:54:31 +02:00
aaeed65c18 application: use LSE for oscillator (and remove other board ifdef 2020-05-31 23:54:31 +02:00
4229353d93 uart: change baudrate and parity to match bluetooth module, which matches USART bootloader 2020-05-31 23:54:31 +02:00
b83ede23ef global: change LED pin so we can use the LSE oscillator 2020-05-31 23:54:31 +02:00
ebbea376a6 application: add action to start embedded bootloader 2020-05-31 23:54:31 +02:00
fdef34e663 application: fix date display and add offset 2020-05-31 23:54:31 +02:00
82 changed files with 1243 additions and 10886 deletions

207
README.md
View File

@ -1,4 +1,4 @@
This firmware template is designed for development boards based around [STM32 F1 series micro-controller](http://www.st.com/web/en/catalog/mmc/FM141/SC1169/SS1031).
The dachtür is a device to restrict access to the dachboden.
project
=======
@ -6,51 +6,161 @@ project
summary
-------
*describe project purpose*
Previously a button allowed to open the building's entrance door and granted access to the dachboden.
Since the dachboden got popular, it is now flooded.
The idea behind the dachtür it to disable this button and replace it with a secret sequence of button presses during certain periods (e.g. when parties are taking place in the dachboden).
It must be installed in the door panel, as described under `connections`.
technology
----------
configure
---------
*described electronic details*
To program the days, times, and button sequence, connect to the dachtür.
It should appear as "dachtuer" Bluetooth (classic) device.
A PIN is required to connect to it.
Once connected, you can use a terminal (such as the "Bluetooth terminal" android application).
Interact with it by entering commands.
- from time to time, update the date (it does not take into account summer and winter time):
~~~
date YYYY-MM-DD HH:MM
~~~
- enter the days on which the access should be restricted (starting with Monday, here only Thursday is active):
~~~
days 0001000
~~~
- enter at which time the restriction should start:
~~~
start 20:00
~~~
- enter at which time the restriction should stop:
~~~
stop 06:00
~~~
- enter the secret button sequence to open the door (here press button 1 then 2):
~~~
password 12
~~~
board
=====
The current implementation uses a [core board](https://wiki.cuvoodoo.info/doku.php?id=stm32f1xx#core_board).
The underlying template also supports following board:
- [Maple Mini](http://leaflabs.com/docs/hardware/maple-mini.html), based on a STM32F103CBT6
- [System Board](https://wiki.cuvoodoo.info/doku.php?id=stm32f1xx#system_board), based on a STM32F103C8T6
- [blue pill](https://wiki.cuvoodoo.info/doku.php?id=stm32f1xx#blue_pill), based on a STM32F103C8T6
- [black pill](https://wiki.cuvoodoo.info/doku.php?id=stm32f1xx#black_pill), based on a STM32F103C8T6
- [core board](https://wiki.cuvoodoo.info/doku.php?id=stm32f1xx#core_board), based on a STM32F103C8T6
- [ST-LINK V2 mini](https://wiki.cuvoodoo.info/doku.php?id=jtag#mini_st-link_v2), a ST-LINK/V2 clone based on a STM32F101C8T6
- [USB-Blaster](https://wiki.cuvoodoo.info/doku.php?id=jtag#armjishu_usb-blaster), an Altera USB-Blaster clone based on a STM32F101C8T6
**Which board is used is defined in the Makefile**.
This is required to map the user LED and button provided on the board
The ST-LINK V2 mini clone has SWD test points on the board.
Because read protection is enabled, you will first need to remove the protection to be able to flash the firmware.
To remove the read protection (and erase flash), run `rake remove_protection` while a SWD adapter is connected.
The Altera USB-Blaster clone has a pin header for SWD and UART1 on the board.
SWD is disabled in the main firmware, and it has read protection.
To be able to flash using SWD (or the serial port), the BOOT0 pin must be set to 1 to boot the system memory install of the flash memory.
To set BOOT0 to 1, apply 3.3 V on R11, between the resistor and the reference designator, when powering the device.
The red LED should stay off while the green LED is on.
Now you can remove the read protection (and erase flash), run `rake remove_protection` while a SWD adapter is connected.
WARNING: If the internal backup battery gets empty and the device looses power, the configuration and date get lost (since there are stored in SRAM).
In this case, replace the battery and reconfigure the device.
connections
===========
Connect the peripherals the following way (STM32F10X signal; STM32F10X pin; peripheral pin; peripheral signal; comment):
On one side there are three XH-2.54 connectors.
- *list board to peripheral pin connections*
2-pin connector: 6-25 AC/DC power input
3-pin connector: opening button (the one already wired)
- 1 (left-most): common side of button (leave the bus bar connected)
- 2 (center): other side of the button (remove the cable)
- 3 (right-most): the cable which was connected to the button
4-pin connector: ring buttons (yet unused)
- 2 left-most pins: to button 1 of door panel
- 2 right-most pins: to button 2 of door panel
On the other side is a USB connector.
This is used to flash and configure the micro-controller.
peripherals
===========
The XH-2.54 2P connector is for the 15V AC power input.
A full bridge rectifier and smoothing capacitor make a DC power supply out of it.
A buck converter module steps it down to 5V.
Under 50 mA of power consumption it is very inefficient.
With no load it has a quiescent current of 37 mA.
The 5V rail provides power to the blue pill, Bluetooth module, and boost converter.
The MT3608-based boost converter steps the voltage up to 9V for the omrom G6E-134P relays.
It is more efficient to re-use the existing 5V than stepping down the 15V because the buck converters drawn a large current under no load.
The XH-2.54 3P is to be connected to door opening button (the installer will know what I mean).
Two omrom G6E-134P relays will take control over the button.
This allows the door button to be used.
At the specified time intervals, this is disconnected.
When the right code is entered, the second relay simulates the button press and opens the door.
The relays are controlled by the board using two 2N7000 n-channel MOSFETs.
The XH-2.54 4P is to be connected with the two buttons.
They are used to enter the secret sequence to open the door.
The [blue pill](https://wiki.cuvoodoo.info/doku.php?id=stm32f1xx#blue_pill), based on a STM32F103C8T6 micro-controller, will handle the logic.
A CR2032 battery is connected through a diode to VBAT.
This keeps the real time clock (RTC) running when there is no power from the panel.
A 3.3V pin is also connected through a diode to VBAT.
This powered the RTC when the board is powered, saving the battery.
The HC-05 Bluetooth module allows to remotely connect to the UART port.
It has been configured (using `hc-05_porg.rb`) to appear as "dachtuer", and requires a PIN to pair.
It offers the Serial Port Profile (SPP) from Bluetooth classic (Bluetooth Low Energy makes little sense).
This allows to communicate with the board without having to remove the panel.
It can be used to configure the opening time slots, days, and button sequence.
It is also possible to update the firmware through it.
A WS2812B LED strip is also connected to the board.
The LEDs should be placed behind the button name shield.
An animation with be shown when pressing the button (only during opening hours).
wiring
======
HC-05 Bluetooth module:
- STATE: no connect
- TXD: PA10/USART1_RX
- RXD: PA9/USART1_TX
- GND: ground
- VCC: 5V
- EN: no connect
CR2032 coin cell battery:
- +: VBAT, though diode (VBAT should also be connected to 3.3V through diode)
- -: ground
LED (because the on-board LED screws the LSE):
- anode: 3.3V, though resistor (1K)
- cathode: PB11
omrom G6E-134P relay (bottom, for button):
- 1 +: 9V
- 6 -: 2N7000 drain
- 7 COM: door button bar
- 10 NC: no connect
- 12 NO: other relay NO
2N7000 p-channel MOSFET (for bottom relay):
- 1 source: ground
- 2 gate: PB6 (pulled low)
- 3 drain: relay -
omrom G6E-134P relay (top, for panel):
- 1 +: 9V
- 6 -: 2N7000 drain
- 7 COM: wire to panel
- 10 NC: door button (where the wire was)
- 12 NO: other relay NO
2N7000 p-channel MOSFET (for top relay):
- 1 source: ground
- 2 gate: PB7 (pulled low)
- 3 drain: relay -
WS2812B RGB LED strip:
- VCC: 5V
- DIN: PB15
- GND: ground
XH-4P:
- 1: ground (for button 1)
- 2: PB8 (for button 1)
- 3: ground (for button 2)
- 4: PB9 (for button 2)
All pins are configured using `define`s in the corresponding source code.
The prototype uses a SZOMK AK-N-01 enclosures salvaged from a J-Link clone.
code
====
@ -81,16 +191,35 @@ The `bootloader` is started first and immediately jumps to the `application` if
The `application` image is the main application and is implemented in `application.c`.
It is up to the application to advertise USB DFU support (i.e. as does the provided USB CDC ACM example).
The `bootloader` image will be flashed using SWD (Serial Wire Debug).
The `bootlaoder` image will be flashed using SWD (Serial Wire Debug).
For that you need an SWD adapter.
The `Makefile` uses a ST-Link V2 programmer along OpenOCD software (default), or Black Magic Probe.
The `Makefile` uses a ST-Link V2 along OpenOCD software.
To flash the `booltoader` using SWD run `rake flash_booloader`.
If the development board uses the CKS32 chip STM32 alternative, use `CPUTAPID=0x2ba01477 rake flash_booloader`.
Once the `bootloader` is flashed it is possible to flash the `application` over USB using the DFU protocol by running `rake flash`.
To force the bootloader to start the DFU mode press the user button or short a pin, depending on the board.
It is also possible to flash the `application` image using SWD by running `rake flash_application`.
It is also possible to flash the application over Bluetooth as follows:
~~~
# start bluetooth
sudo systemctl restart bluetooth
# pair device (you only need to do it once, and you need the PIN)
bluetoothctl
power on
pair 20:15:02:02:16:28
quit
# connect to device
sudo rfcomm bind rfcomm0 20:15:02:02:16:28
# switch to bootloader
echo "embedded" > /dev/rfcomm0
# flash firmware (it always fails the first time)
stm32flash /dev/rfcomm0
stm32flash /dev/rfcomm0 -b 115200 -S 0x08002000 -w application.bin -R
# disconnect from device
sudo rfcomm release rfcomm0
~~~
debug
-----
@ -100,4 +229,4 @@ To start the debugging session run `rake debug`.
USB
---
The firmware offers serial communication over USART1 and USB (using the CDC ACM device class).
The firmware offers serial communication over USART1 (where the Bluetooth module is connected) and USB (using the CDC ACM device class).

View File

@ -193,8 +193,6 @@ OOCD_INTERFACE = ENV["OOCD_INTERFACE"] || (SWD_ADAPTER=="STLINKV2" ? "stlink" :
OOCD_TARGET = "stm32f1x"
# Black Magic Probe port
BMP_PORT = ENV["BMP_PORT"] || "/dev/ttyACM0"
# set CPUTAPID (0x1ba01477 for STM32, 0x2ba01477 for CKS32/APM32)
CPUTAPID = ENV["CPUTAPID"] || "0x1ba01477"
desc "flash application using USB DFU"
task :flash => APPLICATION+".bin" do |t|
@ -205,7 +203,7 @@ desc "remove STM32F1 protection using SWD"
task :remove_protection do
case SWD_ADAPTER
when "STLINKV2"
sh "#{OOCD} --file interface/#{OOCD_INTERFACE}.cfg --command 'transport select hla_swd' --command 'set CPUTAPID #{CPUTAPID}' --file target/#{OOCD_TARGET}.cfg --command 'init' --command 'halt' --command 'reset init' --command 'stm32f1x unlock 0' --command 'reset init' --command 'flash protect 0 0 last off' --command 'reset init' --command 'stm32f1x options_write 0 SWWDG NORSTSTNDBY NORSTSTOP' --command 'reset init' --command 'stm32f1x mass_erase 0' --command 'shutdown'"
sh "#{OOCD} --file interface/#{OOCD_INTERFACE}.cfg --file target/#{OOCD_TARGET}.cfg --command 'init' --command 'reset init' --command 'stm32f1x unlock 0' --command 'reset init' --command 'flash protect 0 0 last off' --command 'reset init' --command 'stm32f1x options_write 0 SWWDG NORSTSTNDBY NORSTSTOP' --command 'reset init' --command 'stm32f1x mass_erase 0' --command 'shutdown'"
when "BMP"
sh "#{GDB} --eval-command='target extended-remote #{BMP_PORT}' --eval-command='set confirm off' --eval-command='monitor swdp_scan' --eval-command='attach 1' --eval-command='monitor option erase' --eval-command='monitor erase_mass' --eval-command='kill' --eval-command='quit'"
end
@ -215,7 +213,7 @@ desc "flash bootloader using SWD"
task :flash_bootloader => BOOTLOADER+".hex" do |t|
case SWD_ADAPTER
when "STLINKV2"
sh "#{OOCD} --file interface/#{OOCD_INTERFACE}.cfg --command 'transport select hla_swd' --command 'set CPUTAPID #{CPUTAPID}' --file target/#{OOCD_TARGET}.cfg --command 'init' --command 'halt' --command 'reset init' --command 'flash erase_sector 0 0 last' --command 'flash write_image erase #{t.source}' --command 'reset' --command 'shutdown'"
sh "#{OOCD} --file interface/#{OOCD_INTERFACE}.cfg --file target/#{OOCD_TARGET}.cfg --command 'init' --command 'reset init' --command 'flash erase_sector 0 0 last' --command 'flash write_image erase #{t.source}' --command 'reset' --command 'shutdown'"
when "BMP"
sh "#{GDB} --eval-command='target extended-remote #{BMP_PORT}' --eval-command='set confirm off' --eval-command='monitor swdp_scan' --eval-command='attach 1' --eval-command='monitor erase_mass' --eval-command='load' --eval-command='kill' --eval-command='quit' #{t.source}"
end
@ -225,7 +223,7 @@ desc "flash application using SWD"
task :flash_application => APPLICATION+".hex" do |t|
case SWD_ADAPTER
when "STLINKV2"
sh "#{OOCD} --file interface/#{OOCD_INTERFACE}.cfg --command 'transport select hla_swd' --command 'set CPUTAPID #{CPUTAPID}' --file target/#{OOCD_TARGET}.cfg --command 'adapter speed 100' --command 'init' --command 'halt' --command 'reset init' --command 'flash write_image erase #{t.source}' --command 'reset' --command 'shutdown'"
sh "#{OOCD} --file interface/#{OOCD_INTERFACE}.cfg --file target/#{OOCD_TARGET}.cfg --command 'init' --command 'reset init' --command 'flash write_image erase #{t.source}' --command 'reset' --command 'shutdown'"
when "BMP"
sh "#{GDB} --eval-command='target extended-remote #{BMP_PORT}' --eval-command='set confirm off' --eval-command='monitor swdp_scan' --eval-command='attach 1' --eval-command='load' --eval-command='kill' --eval-command='quit' #{t.source}"
end
@ -237,7 +235,7 @@ task :debug => APPLICATION+".elf" do |t|
case SWD_ADAPTER
when "STLINKV2"
# for GDB to work with openOCD the firmware needs to be reloaded
exec("#{GDB} --eval-command='target remote | #{OOCD} --file interface/#{OOCD_INTERFACE}.cfg --command \"transport select hla_swd\" --command \"set CPUTAPID #{CPUTAPID}\" --file target/#{OOCD_TARGET}.cfg --command \"gdb_port pipe; log_output /dev/null; init\"' #{t.source}")
exec("#{GDB} --eval-command='target remote | #{OOCD} --file interface/#{OOCD_INTERFACE}.cfg --file target/#{OOCD_TARGET}.cfg --command \"gdb_port pipe; log_output /dev/null; init\"' --eval-command='monitor reset halt' --eval-command='load' --eval-command='monitor reset init' #{t.source}")
when "BMP"
exec("#{GDB} --eval-command='target extended-remote #{BMP_PORT}' --eval-command='monitor version' --eval-command='monitor swdp_scan' --eval-command='attach 1' #{t.source}")
end
@ -249,7 +247,7 @@ task :debug_bootloader => BOOTLOADER+".elf" do |t|
case SWD_ADAPTER
when "STLINKV2"
# for GDB to work with openOCD the firmware needs to be reloaded
exec("#{GDB} --eval-command='target remote | #{OOCD} --file interface/#{OOCD_INTERFACE}.cfg --command \"transport select hla_swd\" --command \"set CPUTAPID #{CPUTAPID}\" --file target/#{OOCD_TARGET}.cfg --command \"gdb_port pipe; log_output /dev/null; init\"' --eval-command='monitor reset init' #{t.source}")
exec("#{GDB} --eval-command='target remote | #{OOCD} --file interface/#{OOCD_INTERFACE}.cfg --file target/#{OOCD_TARGET}.cfg --command \"gdb_port pipe; log_output /dev/null; init\"' --eval-command='monitor reset halt' --eval-command='load' --eval-command='monitor reset init' #{t.source}")
when "BMP"
exec("#{GDB} --eval-command='target extended-remote #{BMP_PORT}' --eval-command='monitor version' --eval-command='monitor swdp_scan' --eval-command='attach 1' #{t.source}")
end

View File

@ -1,7 +1,20 @@
/** STM32F1 application example
/* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/** dachboden front panel access control
* @file
* @author King Kévin <kingkevin@cuvoodoo.info>
* @copyright SPDX-License-Identifier: GPL-3.0-or-later
* @date 2016-2020
*/
@ -24,16 +37,17 @@
#include <libopencm3/stm32/dbgmcu.h> // debug utilities
#include <libopencm3/stm32/desig.h> // design utilities
#include <libopencm3/stm32/flash.h> // flash utilities
#include <libopencm3/stm32/f1/bkp.h> // backup domain utilities
#include <libopencm3/stm32/timer.h> // timer utilities
/* own libraries */
#include "global.h" // board definitions
#include "print.h" // printing utilities
#if !defined(STLINKV2)
#include "uart.h" // USART utilities
#endif
#include "usb_cdcacm.h" // USB CDC ACM utilities
#include "terminal.h" // handle the terminal interface
#include "menu.h" // menu utilities
#include "led_ws2812b.h" // WS2812B RGB LED control
/** watchdog period in ms */
#define WATCHDOG_PERIOD 10000
@ -41,16 +55,12 @@
/** set to 0 if the RTC is reset when the board is powered on, only indicates the uptime
* set to 1 if VBAT can keep the RTC running when the board is unpowered, indicating the date and time
*/
#if defined(CORE_BOARD)
#define RTC_DATE_TIME 1
#else
#define RTC_DATE_TIME 0
#endif
/** number of RTC ticks per second
* @note use integer divider of oscillator to keep second precision
*/
#define RTC_TICKS_SECOND 4
#define RTC_TICKS_SECOND 1
#if defined(RTC_DATE_TIME) && RTC_DATE_TIME
/** the start time from which to RTC ticks count
@ -65,9 +75,82 @@ static time_t time_start = 0;
/** @defgroup main_flags flag set in interrupts to be processed in main task
* @{
*/
static volatile bool rtc_internal_tick_flag = false; /**< flag set when internal RTC ticked */
volatile bool rtc_internal_tick_flag = false; /**< flag set when internal RTC ticked */
/** @} */
/** GPIO pin connected to relay, used to control button connection to panel */
#define RELAY_PANEL_PIN PB6
/** GPIO pin connected to relay, used to simulate button press */
#define RELAY_BUTTON_PIN PB7
/** GPIO for button 1 */
#define BUTTON1_PIN PB9
/** GPIO for button 2 */
#define BUTTON2_PIN PB8
/** which button has been pressed */
volatile uint8_t button_pressed = 0;
/** if we apply the opening policy */
bool opening_apply = false;
uint8_t pattern_length = 0;
static struct opening_settings_t {
uint8_t days; /**< which days of the week it door access applies (bit 7 = Monday) */
uint16_t start_time; /**< at which minutes of the day to start */
uint16_t stop_time; /**< at which minutes of the day to stop */
uint8_t button_pattern[10]; /**< sequence of buttons to press to open the door */
} opening_settings;
/** timer to generate the ticks for the button LED animations */
#define LED_ANIMATION_TIMER 2
/** number of timer ticks passed, for the LED animation */
static volatile uint8_t led_animation_ticks = 0;
/** the button LED animation for the rust fade (duration in ticks, R, G, B) */
static const uint8_t rust_animation[][4] = {
{0, 0, 0, 0},
{1, 0xb7 / 10 * 1, 0x41 / 10 * 1, 0x0e / 10 * 1},
{1, 0xb7 / 10 * 2, 0x41 / 10 * 2, 0x0e / 10 * 2},
{1, 0xb7 / 10 * 3, 0x41 / 10 * 3, 0x0e / 10 * 3},
{1, 0xb7 / 10 * 4, 0x41 / 10 * 4, 0x0e / 10 * 4},
{1, 0xb7 / 10 * 5, 0x41 / 10 * 5, 0x0e / 10 * 5},
{1, 0xb7 / 10 * 4, 0x41 / 10 * 4, 0x0e / 10 * 4},
{1, 0xb7 / 10 * 3, 0x41 / 10 * 3, 0x0e / 10 * 3},
{1, 0xb7 / 10 * 2, 0x41 / 10 * 2, 0x0e / 10 * 2},
{1, 0xb7 / 10 * 1, 0x41 / 10 * 1, 0x0e / 10 * 1},
{0, 0, 0, 0},
};
/** the button LED animation for the strobe (duration in ticks, R, G, B) */
static const uint8_t strobe_animation[][4] = {
{0, 0, 0, 0},
{1, 0xff / 2, 0xff / 2, 0xff / 2},
{2, 0, 0, 0},
{1, 0xff / 2, 0xff / 2, 0xff / 2},
{0, 0, 0, 0},
};
/** save current opening_settings into SRAM */
static void save_opening_settings(void)
{
BKP_DR1 = 0; // invalid saved settings
BKP_DR2 = opening_settings.days & 0x7f;
BKP_DR3 = opening_settings.start_time;
BKP_DR4 = opening_settings.stop_time;
BKP_DR5 = opening_settings.button_pattern[0];
BKP_DR6 = opening_settings.button_pattern[1];
BKP_DR7 = opening_settings.button_pattern[2];
BKP_DR8 = opening_settings.button_pattern[3];
BKP_DR9 = opening_settings.button_pattern[4];
BKP_DR10 = opening_settings.button_pattern[5];
BKP_DR11 = opening_settings.button_pattern[6];
BKP_DR12 = opening_settings.button_pattern[7];
BKP_DR13 = opening_settings.button_pattern[8];
BKP_DR14 = opening_settings.button_pattern[9];
BKP_DR1 = 0x4223; //validate saved setting
}
size_t putc(char c)
{
size_t length = 0; // number of characters printed
@ -120,7 +203,175 @@ static void command_reset(void* argument);
/** switch to DFU bootloader
* @param[in] argument no argument required
*/
static void command_bootloader(void* argument);
static void command_bootloader_dfu(void* argument);
/** switch to system memory / embedded USART bootloader
* @param[in] argument no argument required
*/
static void command_bootloader_embedded(void* argument);
/** show/set on which days the access policy applies
* @param[in] argument 7x0/1 to enable day of the week, starting with Monday (optional)
*/
static void command_days(void* argument)
{
const char* days = (char*)argument; // argument is optional days
if (NULL != argument) { // days are provided, parse and save them
bool valid = (7 == strlen(days)); // verify input string
for (uint8_t day = 0; day < 7 && valid; day++) {
if (days[day] != '0' && days[day] != '1') {
valid = false;
}
}
if (valid) { // save provided settings
// parse new days
opening_settings.days = 0;
for (uint8_t day = 0; day < 7; day++) {
if ('1' == days[day]) {
opening_settings.days |= (1 << (6 - day));
}
}
save_opening_settings(); // save days
puts("days saved\n");
} else {
puts("provide exactly 7 times 0 (off) or 1 (on). 1st digit for Monday, 7th digit for Sunday\n");
}
}
// display current days
printf("opening days: %07b\n", opening_settings.days);
const char* day_names[] = {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"};
for (uint8_t day = 0; day < LENGTH(day_names); day++) {
printf("- %s: %s\n", day_names[day], (opening_settings.days & (1 << (6 - day))) ? "on" : "off");
}
}
/** show/set on which time the access policy starts applying
* @param[in] argument string with time of day, optional
*/
static void command_start(void* argument)
{
const char* time = (char*)argument; // argument is optional time
if (NULL != argument) { // days are provided, parse and save them
bool valid = (5 == strlen(time)); // verify input string
if (!(valid && isdigit((int8_t)time[0]) && isdigit((int8_t)time[1]) && ':' == time[2] && isdigit((int8_t)time[3]) && isdigit((int8_t)time[4]))) {
valid = false;
}
if (valid) { // save provided settings
opening_settings.start_time = 0;
opening_settings.start_time += (time[4] - '0') * 1;
opening_settings.start_time += (time[3] - '0') * 10;
opening_settings.start_time += (time[1] - '0') * 60;
opening_settings.start_time += (time[0] - '0') * 600;
save_opening_settings(); // save days
puts("start time saved\n");
} else {
puts("provide time in HH:MM format\n");
}
}
printf("start time: %02u:%02u\n", opening_settings.start_time / 60, opening_settings.start_time % 60);
}
/** show/set on which time the access policy stops applying
* @param[in] argument string with time of day, optional
*/
static void command_stop(void* argument)
{
const char* time = (char*)argument; // argument is optional time
if (NULL != argument) { // days are provided, parse and save them
bool valid = (5 == strlen(time)); // verify input string
if (!(valid && isdigit((int8_t)time[0]) && isdigit((int8_t)time[1]) && ':' == time[2] && isdigit((int8_t)time[3]) && isdigit((int8_t)time[4]))) {
valid = false;
}
if (valid) { // save provided settings
opening_settings.stop_time = 0;
opening_settings.stop_time += (time[4] - '0') * 1;
opening_settings.stop_time += (time[3] - '0') * 10;
opening_settings.stop_time += (time[1] - '0') * 60;
opening_settings.stop_time += (time[0] - '0') * 600;
save_opening_settings(); // save days
puts("stop time saved\n");
} else {
puts("provide time in HH:MM format\n");
}
}
printf("stop time: %02u:%02u\n", opening_settings.stop_time / 60, opening_settings.stop_time % 60);
}
/** open door by simulating button press
* @param[in] argument not used
*/
static void command_open(void* argument)
{
(void)argument; // we won't use the argument
gpio_set(GPIO_PORT(RELAY_PANEL_PIN), GPIO_PIN(RELAY_PANEL_PIN)); // set high to activate relay and take control over the button
gpio_set(GPIO_PORT(RELAY_BUTTON_PIN), GPIO_PIN(RELAY_BUTTON_PIN)); // set high to activate relay an simulate button press
sleep_ms(1000); // hold button a bit
gpio_clear(GPIO_PORT(RELAY_BUTTON_PIN), GPIO_PIN(RELAY_BUTTON_PIN)); // set low to deactivate relay and release button
if (!opening_apply) {
gpio_clear(GPIO_PORT(RELAY_PANEL_PIN), GPIO_PIN(RELAY_PANEL_PIN)); // set low to deactivate relay and git control back to button
}
}
/** show/set button pattern
* @param[in] argument sequence of 1/2
*/
static void command_pattern(void* argument)
{
const char* pattern = (char*)argument; // argument is optional pattern
if (NULL != argument) { // pattern provided
bool valid = (LENGTH(opening_settings.button_pattern) >= strlen(pattern)); // verify input string
for (uint8_t i = 0; i < strlen(pattern) && valid; i++) {
if ('1' != pattern[i] && '2' != pattern[i]) {
valid = false;
}
}
if (valid) { // save provided settings
// reset pattern
for (uint8_t i = 0; i < LENGTH(opening_settings.button_pattern); i++) {
opening_settings.button_pattern[i] = 0;
}
// save new pattern
for (uint8_t i = 0; i < strlen(pattern); i++) {
opening_settings.button_pattern[i] = pattern[i] - '0';
}
save_opening_settings(); // save days
puts("button sequence saved\n");
} else {
printf("provide buttons sequence of up to %u 1 or 2\n", LENGTH(opening_settings.button_pattern));
}
for (pattern_length = 0; pattern_length < LENGTH(opening_settings.button_pattern) && opening_settings.button_pattern[pattern_length]; pattern_length++);
}
if (0 == opening_settings.button_pattern[0]) {
puts("no button sequence set\n");
} else {
puts("button sequence: ");
for (uint8_t i = 0; i < LENGTH(opening_settings.button_pattern) && opening_settings.button_pattern[i]; i++) {
putc(opening_settings.button_pattern[i] + '0');
}
putc('\n');
}
}
/** test LEDs
* @param[in] argument "on" or "off"
*/
static void command_led(void* argument)
{
const char* onoff = (char*)argument; // if it should be switched on or off
if (NULL == onoff || 0 == strlen(onoff)) {
puts("say if the LEDs should be switched on or off\n");
} else if (0 == strcmp(onoff, "on")) {
for (uint8_t led = 0; led < LED_WS2812B_LEDS; led++) {
led_ws2812b_set_rgb(led, 0x20, 0x20 , 0x20);
}
} else if (0 == strcmp(onoff, "off")) {
for (uint8_t led = 0; led < LED_WS2812B_LEDS; led++) {
led_ws2812b_set_rgb(led, 0, 0 , 0);
}
} else {
printf("unknown argument %s\n", onoff);
}
}