application: complete enforecer application, and documentation
This commit is contained in:
parent
a5a0ae84d1
commit
cc75867942
88
README.md
88
README.md
|
@ -1,4 +1,5 @@
|
||||||
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).
|
This is the firmware for the sound lever enforcer.
|
||||||
|
It will cut the power of speakers when it's too loud.
|
||||||
|
|
||||||
project
|
project
|
||||||
=======
|
=======
|
||||||
|
@ -6,48 +7,75 @@ project
|
||||||
summary
|
summary
|
||||||
-------
|
-------
|
||||||
|
|
||||||
*describe project purpose*
|
The sound level enforcer receives measurements from a sound level meter over Bluetooth.
|
||||||
|
The sound level is then show on a display (0 if it is not connected or receives no data).
|
||||||
|
If this level is below the threshold configured, the display is dim.
|
||||||
|
If the level is above the threshold configured, the brightness is higher.
|
||||||
|
If the level is above the threshold configured, for a set amount of time, a relay it activated.
|
||||||
|
The relay's purpose is to cut the power of speakers/mixer.
|
||||||
|
"too loud" will be shown on the display, and the button will light up.
|
||||||
|
Press the button to reset the device.
|
||||||
|
The relay will be deactivated, and the cycle starts again.
|
||||||
|
|
||||||
|
When powered up or reset, the display will show the sound level threshold (followed by the unit "dBa"), and duration (followed by the unit "dBa").
|
||||||
|
To change the sound level threshold, enter "threshold xxx" on the serial interface (over USB, or UART).
|
||||||
|
To change the sound level duration, enter "duration xxx" on the serial interface (over USB, or UART).
|
||||||
|
|
||||||
technology
|
technology
|
||||||
----------
|
----------
|
||||||
|
|
||||||
*described electronic details*
|
The firmware runs on a [black pill](https://wiki.cuvoodoo.info/doku.php?id=stm32f1xx#black_pill) development board.
|
||||||
|
It is based on a STM32F103C8T6 micro-controller.
|
||||||
|
This will do all the processing and control the peripherals.
|
||||||
|
|
||||||
board
|
The Bluetooth module is a HC-05.
|
||||||
=====
|
It should be configured to automatically connect to the sound level meter.
|
||||||
|
It should receive the sound level over Bluetooth in the format "123.4 dBa\n".
|
||||||
|
The measurement will be forwarded to the micro-controller over the UART part configured at 115200 bps 8N1.
|
||||||
|
|
||||||
The current implementation uses a [core board](https://wiki.cuvoodoo.info/doku.php?id=stm32f1xx#core_board).
|
This does not use a Bluetooth Low Energy (BLE) module because it does not fit the needs.
|
||||||
|
There is no need to save energy since the device needs permanent power just for the display.
|
||||||
|
There is a constant stream of data (not fitting BLE principles).
|
||||||
|
The is a specified Classic Bluetooth profile for serial data: Serial Port Profile (SPP).
|
||||||
|
BLE module use non-standard GATT characteristics for serial data transfer.
|
||||||
|
|
||||||
The underlying template also supports following board:
|
The display is a 4-digit 7-segment LED display.
|
||||||
|
This is controlled by a TM1367.
|
||||||
|
|
||||||
- [Maple Mini](http://leaflabs.com/docs/hardware/maple-mini.html), based on a STM32F103CBT6
|
The relay is a SRD-05VDC-SL-C module (250V 10A).
|
||||||
- [System Board](https://wiki.cuvoodoo.info/doku.php?id=stm32f1xx#system_board), based on a STM32F103C8T6
|
Connect it to the device using a 2.5 mm jack.
|
||||||
- [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**.
|
The momentary button should have a built-in LED.
|
||||||
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.
|
|
||||||
|
|
||||||
connections
|
connections
|
||||||
===========
|
===========
|
||||||
|
|
||||||
Connect the peripherals the following way (STM32F10X signal; STM32F10X pin; peripheral pin; peripheral signal; comment):
|
Connect the peripherals as described below.
|
||||||
|
|
||||||
- *list board to peripheral pin connections*
|
HC-05 Bluetooth SPP module:
|
||||||
|
- STATE: no connect
|
||||||
|
- RX: no connect
|
||||||
|
- TX: USART3_RX/PB11
|
||||||
|
- GND: ground
|
||||||
|
- VCC: 5V
|
||||||
|
- EN: no connect
|
||||||
|
|
||||||
|
button (momentary, with LED)
|
||||||
|
- +: 5V
|
||||||
|
- -: 470 Ohm resistor to PB12 (sometimes the resistor is already built in the button)
|
||||||
|
- S: GND
|
||||||
|
- S: NRST
|
||||||
|
|
||||||
|
7-segment display TM1637:
|
||||||
|
- GND: ground
|
||||||
|
- VCC: 5V
|
||||||
|
- DIO: PB13
|
||||||
|
- CLK: PB14
|
||||||
|
|
||||||
|
relay, connected to 2.5 mm TRS jack:
|
||||||
|
- tip, VCC: 5V
|
||||||
|
- ring, IN: PB15
|
||||||
|
- sleeve, GND: ground
|
||||||
|
|
||||||
All pins are configured using `define`s in the corresponding source code.
|
All pins are configured using `define`s in the corresponding source code.
|
||||||
|
|
||||||
|
@ -83,7 +111,7 @@ It is up to the application to advertise USB DFU support (i.e. as does the provi
|
||||||
|
|
||||||
The `bootlaoder` 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.
|
For that you need an SWD adapter.
|
||||||
The `Makefile` uses a Black Magic Probe (per default), or a ST-Link V2 along OpenOCD software.
|
The `Makefile` uses a ST-Link V2 along OpenOCD software.
|
||||||
To flash the `booltoader` using SWD run `rake flash_booloader`.
|
To flash the `booltoader` using SWD run `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`.
|
Once the `bootloader` is flashed it is possible to flash the `application` over USB using the DFU protocol by running `rake flash`.
|
||||||
|
|
292
application.c
292
application.c
|
@ -12,7 +12,7 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
/** STM32F1 application example
|
/** sound level enforcer
|
||||||
* @file
|
* @file
|
||||||
* @author King Kévin <kingkevin@cuvoodoo.info>
|
* @author King Kévin <kingkevin@cuvoodoo.info>
|
||||||
* @date 2016-2020
|
* @date 2016-2020
|
||||||
|
@ -23,7 +23,8 @@
|
||||||
#include <stdlib.h> // standard utilities
|
#include <stdlib.h> // standard utilities
|
||||||
#include <string.h> // string utilities
|
#include <string.h> // string utilities
|
||||||
#include <time.h> // date/time utilities
|
#include <time.h> // date/time utilities
|
||||||
#include <ctype.h> // utilities to check chars
|
#include <ctype.h> // utilities to check char
|
||||||
|
#include <math.h> // for rounding floats
|
||||||
|
|
||||||
/* STM32 (including CM3) libraries */
|
/* STM32 (including CM3) libraries */
|
||||||
#include <libopencmsis/core_cm3.h> // Cortex M3 utilities
|
#include <libopencmsis/core_cm3.h> // Cortex M3 utilities
|
||||||
|
@ -48,6 +49,8 @@
|
||||||
#include "terminal.h" // handle the terminal interface
|
#include "terminal.h" // handle the terminal interface
|
||||||
#include "menu.h" // menu utilities
|
#include "menu.h" // menu utilities
|
||||||
#include "led_tm1637.h" // 7-segment display
|
#include "led_tm1637.h" // 7-segment display
|
||||||
|
#include "spp_rx.h" // Bluetooth SPP input
|
||||||
|
#include "flash_internal.h" // settings storage
|
||||||
|
|
||||||
/** watchdog period in ms */
|
/** watchdog period in ms */
|
||||||
#define WATCHDOG_PERIOD 10000
|
#define WATCHDOG_PERIOD 10000
|
||||||
|
@ -75,6 +78,25 @@ static time_t time_start = 0;
|
||||||
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 */
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
|
/** buffer for the data received over Bluetooth from the sound level meter */
|
||||||
|
static char spp_input_buffer[16];
|
||||||
|
/** how much received data is buffered */
|
||||||
|
static uint8_t spp_input_i = 0;
|
||||||
|
|
||||||
|
/** pin to control relay (active low) */
|
||||||
|
#define RELAY_PIN PB15
|
||||||
|
|
||||||
|
/** default sound level threshold (in dBa) */
|
||||||
|
#define SOUND_LEVEL_THRESHOLD 100
|
||||||
|
/** configured sound level threshold (in dBa) */
|
||||||
|
static uint8_t sound_level_threshold = SOUND_LEVEL_THRESHOLD;
|
||||||
|
/** default sound level duration (in seconds) */
|
||||||
|
#define SOND_LEVEL_DURATION 10
|
||||||
|
/** configured sound level duration (in seconds) */
|
||||||
|
static uint8_t sound_level_duration = SOND_LEVEL_DURATION;
|
||||||
|
/** if we show the received sound level value */
|
||||||
|
static bool sound_level_show = false;
|
||||||
|
|
||||||
size_t putc(char c)
|
size_t putc(char c)
|
||||||
{
|
{
|
||||||
size_t length = 0; // number of characters printed
|
size_t length = 0; // number of characters printed
|
||||||
|
@ -129,6 +151,90 @@ static void command_reset(void* argument);
|
||||||
*/
|
*/
|
||||||
static void command_bootloader(void* argument);
|
static void command_bootloader(void* argument);
|
||||||
|
|
||||||
|
/** load sound level threshold and duration settings from flash
|
||||||
|
* @return if values are loaded from flash (else set to default)
|
||||||
|
*/
|
||||||
|
static bool sound_level_load(void)
|
||||||
|
{
|
||||||
|
uint8_t eeprom_data[4] = {0};
|
||||||
|
const bool eeprom_read = flash_internal_eeprom_read(eeprom_data, sizeof(eeprom_data));
|
||||||
|
if (eeprom_read) {
|
||||||
|
eeprom_data[1] ^= 0xff; // xor value (sort of checksum)
|
||||||
|
eeprom_data[3] ^= 0xff; // xor value (sort of checksum)
|
||||||
|
if (eeprom_data[0] == eeprom_data[1] && eeprom_data[2] == eeprom_data[3]) {
|
||||||
|
sound_level_threshold = eeprom_data[0];
|
||||||
|
sound_level_duration = eeprom_data[2];
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sound_level_threshold = SOUND_LEVEL_THRESHOLD;
|
||||||
|
sound_level_duration = SOND_LEVEL_DURATION;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** save sound level threshold and duration settings into flash
|
||||||
|
* @return if succeeded
|
||||||
|
*/
|
||||||
|
static bool sound_level_save(void)
|
||||||
|
{
|
||||||
|
const uint8_t eeprom_data[4] = {
|
||||||
|
sound_level_threshold,
|
||||||
|
sound_level_threshold ^ 0xff,
|
||||||
|
sound_level_duration,
|
||||||
|
sound_level_duration ^ 0xff,
|
||||||
|
};
|
||||||
|
const int32_t rc = flash_internal_eeprom_write(eeprom_data, sizeof(eeprom_data));
|
||||||
|
if (rc < 0) {
|
||||||
|
printf("error saving sound level data: %d\n", rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc == sizeof(eeprom_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** set sound level threshold
|
||||||
|
* @param[in] argument sound level threshold
|
||||||
|
*/
|
||||||
|
static void command_sound_level_threshold(void* argument)
|
||||||
|
{
|
||||||
|
if (argument) { // tachometer value has been provided
|
||||||
|
const uint32_t value = *(uint32_t*)argument; // get target sound level threshold value
|
||||||
|
sound_level_threshold = value;
|
||||||
|
if (!sound_level_save()) {
|
||||||
|
puts("could not save sound level threshold\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("sound level threshold set to %u dBa\n", sound_level_threshold);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** set sound level duration
|
||||||
|
* @param[in] argument sound level duration
|
||||||
|
*/
|
||||||
|
static void command_sound_level_duration(void* argument)
|
||||||
|
{
|
||||||
|
if (argument) { // tachometer value has been provided
|
||||||
|
const uint32_t value = *(uint32_t*)argument; // get target sound level duration value
|
||||||
|
sound_level_duration = value;
|
||||||
|
if (!sound_level_save()) {
|
||||||
|
puts("could not save sound level duration\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("sound level duration set to %u s\n", sound_level_duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** show/hide received sound level
|
||||||
|
* @param[in] argument not used
|
||||||
|
*/
|
||||||
|
static void command_show(void* argument)
|
||||||
|
{
|
||||||
|
(void)argument; // we won't use the argument
|
||||||
|
sound_level_show = !sound_level_show; // toggle setting
|
||||||
|
puts(sound_level_show ? "show" : "hide");
|
||||||
|
puts(" received sound level\n");
|
||||||
|
}
|
||||||
|
|
||||||
/** list of all supported commands */
|
/** list of all supported commands */
|
||||||
static const struct menu_command_t menu_commands[] = {
|
static const struct menu_command_t menu_commands[] = {
|
||||||
{
|
{
|
||||||
|
@ -157,7 +263,7 @@ static const struct menu_command_t menu_commands[] = {
|
||||||
},
|
},
|
||||||
#if RTC_DATE_TIME
|
#if RTC_DATE_TIME
|
||||||
{
|
{
|
||||||
.shortcut = 'd',
|
.shortcut = 'D',
|
||||||
.name = "date",
|
.name = "date",
|
||||||
.command_description = "show/set date and time",
|
.command_description = "show/set date and time",
|
||||||
.argument = MENU_ARGUMENT_STRING,
|
.argument = MENU_ARGUMENT_STRING,
|
||||||
|
@ -181,6 +287,30 @@ static const struct menu_command_t menu_commands[] = {
|
||||||
.argument_description = NULL,
|
.argument_description = NULL,
|
||||||
.command_handler = &command_bootloader,
|
.command_handler = &command_bootloader,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.shortcut = 't',
|
||||||
|
.name = "threshold",
|
||||||
|
.command_description = "get/set sound level threshold (in dBa)",
|
||||||
|
.argument = MENU_ARGUMENT_UNSIGNED,
|
||||||
|
.argument_description = "[value]",
|
||||||
|
.command_handler = &command_sound_level_threshold,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.shortcut = 'd',
|
||||||
|
.name = "duration",
|
||||||
|
.command_description = "get/set sound level duration (in seconds)",
|
||||||
|
.argument = MENU_ARGUMENT_UNSIGNED,
|
||||||
|
.argument_description = "[value]",
|
||||||
|
.command_handler = &command_sound_level_duration,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.shortcut = 's',
|
||||||
|
.name = "show",
|
||||||
|
.command_description = "show/hide received sound level",
|
||||||
|
.argument = MENU_ARGUMENT_NONE,
|
||||||
|
.argument_description = NULL,
|
||||||
|
.command_handler = &command_show,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static void command_help(void* argument)
|
static void command_help(void* argument)
|
||||||
|
@ -200,34 +330,34 @@ static void command_version(void* argument)
|
||||||
// 0x414: high-density, 256-512 kB flash
|
// 0x414: high-density, 256-512 kB flash
|
||||||
// 0x430: XL-density, 768-1024 kB flash
|
// 0x430: XL-density, 768-1024 kB flash
|
||||||
// 0x418: connectivity
|
// 0x418: connectivity
|
||||||
puts("device family: ");
|
printf("device family: ");
|
||||||
switch (DBGMCU_IDCODE & DBGMCU_IDCODE_DEV_ID_MASK) {
|
switch (DBGMCU_IDCODE & DBGMCU_IDCODE_DEV_ID_MASK) {
|
||||||
case 0: // this is a known issue document in STM32F10xxC/D/E Errata sheet, without workaround
|
case 0: // this is a known issue document in STM32F10xxC/D/E Errata sheet, without workaround
|
||||||
puts("unreadable\n");
|
printf("unreadable\n");
|
||||||
break;
|
break;
|
||||||
case 0x412:
|
case 0x412:
|
||||||
puts("low-density\n");
|
printf("low-density\n");
|
||||||
break;
|
break;
|
||||||
case 0x410:
|
case 0x410:
|
||||||
puts("medium-density\n");
|
printf("medium-density\n");
|
||||||
break;
|
break;
|
||||||
case 0x414:
|
case 0x414:
|
||||||
puts("high-density\n");
|
printf("high-density\n");
|
||||||
break;
|
break;
|
||||||
case 0x430:
|
case 0x430:
|
||||||
puts("XL-density\n");
|
printf("XL-density\n");
|
||||||
break;
|
break;
|
||||||
case 0x418:
|
case 0x418:
|
||||||
puts("connectivity\n");
|
printf("connectivity\n");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
puts("unknown\n");
|
printf("unknown\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// show flash size
|
// show flash size
|
||||||
puts("flash size: ");
|
printf("flash size: ");
|
||||||
if (0xffff == DESIG_FLASH_SIZE) {
|
if (0xffff == DESIG_FLASH_SIZE) {
|
||||||
puts("unknown (probably a defective micro-controller\n");
|
printf("unknown (probably a defective micro-controller\n");
|
||||||
} else {
|
} else {
|
||||||
printf("%u KB\n", DESIG_FLASH_SIZE);
|
printf("%u KB\n", DESIG_FLASH_SIZE);
|
||||||
}
|
}
|
||||||
|
@ -316,6 +446,36 @@ static void process_command(char* str)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** parse and display sound level value
|
||||||
|
* @param[io] str line with dBA measurement
|
||||||
|
* @return parsed measurement (0 if failed)
|
||||||
|
* @warning modifies str
|
||||||
|
*/
|
||||||
|
static uint8_t parse_measurement(char* str)
|
||||||
|
{
|
||||||
|
if (strlen(str) < 5) { // minimum size for a valid message
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const char* delimiter = " "; // words are separated by spaces
|
||||||
|
const char* value_s = strtok(str, delimiter); // get measurement value
|
||||||
|
if (!value_s) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const char* unit = strtok(NULL, delimiter); // get measurement unit
|
||||||
|
if (!unit) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (strncmp("dBa", unit, 3)) { // the measurement unit is the right one
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const double value_f = atof(value_s); // get measurement value
|
||||||
|
if (isnan(value_f) || value_f < 0.1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const uint8_t value_i = round(value_f); // get rounded measurement value
|
||||||
|
return value_i;
|
||||||
|
}
|
||||||
|
|
||||||
/** program entry point
|
/** program entry point
|
||||||
* this is the firmware function started by the micro-controller
|
* this is the firmware function started by the micro-controller
|
||||||
*/
|
*/
|
||||||
|
@ -342,7 +502,7 @@ void main(void)
|
||||||
uart_setup(); // setup USART (for printing)
|
uart_setup(); // setup USART (for printing)
|
||||||
#endif
|
#endif
|
||||||
usb_cdcacm_setup(); // setup USB CDC ACM (for printing)
|
usb_cdcacm_setup(); // setup USB CDC ACM (for printing)
|
||||||
puts("\nwelcome to the CuVoodoo sound lever meter display\n"); // print welcome message
|
puts("\nwelcome to the CuVoodoo sound lever enforcer\n"); // print welcome message
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
// show reset cause
|
// show reset cause
|
||||||
|
@ -395,13 +555,49 @@ void main(void)
|
||||||
time_start = rtc_get_counter_val(); // get start time from internal RTC
|
time_start = rtc_get_counter_val(); // get start time from internal RTC
|
||||||
puts("OK\n");
|
puts("OK\n");
|
||||||
|
|
||||||
// setup display
|
puts("setup relay: ");
|
||||||
printf("setup 7-segment display: ");
|
gpio_set(GPIO_PORT(RELAY_PIN), GPIO_PIN(RELAY_PIN)); // idle not activated
|
||||||
|
gpio_set_mode(GPIO_PORT(RELAY_PIN), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO_PIN(RELAY_PIN)); // set pin as output (sink to enable)
|
||||||
|
puts("OK\n");
|
||||||
|
|
||||||
|
puts("setup 7-segment display: ");
|
||||||
led_tm1637_setup();
|
led_tm1637_setup();
|
||||||
led_tm1637_brightness(LED_TM1637_14DIV16);
|
led_tm1637_brightness(LED_TM1637_14DIV16); // set maximum brightness
|
||||||
led_tm1637_time(88, 88);
|
led_tm1637_time(88, 88); // show test pattern
|
||||||
led_tm1637_on();
|
led_tm1637_on();
|
||||||
printf("OK\n");
|
puts("OK\n");
|
||||||
|
|
||||||
|
puts("setup SPP receiver: ");
|
||||||
|
spp_rx_setup();
|
||||||
|
puts("OK\n");
|
||||||
|
|
||||||
|
puts("read sound level settings: ");
|
||||||
|
flash_internal_eeprom_setup(1); // dedicate one page to store the settings
|
||||||
|
if (sound_level_load()) {
|
||||||
|
puts("set");
|
||||||
|
} else {
|
||||||
|
puts("default");
|
||||||
|
}
|
||||||
|
puts(" values\n");
|
||||||
|
command_sound_level_threshold(NULL); // show value
|
||||||
|
command_sound_level_duration(NULL); // show value
|
||||||
|
|
||||||
|
// show sound level
|
||||||
|
iwdg_reset(); // kick the dog
|
||||||
|
led_tm1637_number(sound_level_threshold, false); // display threshold
|
||||||
|
sleep_ms(1000); // wait some time for the user to read
|
||||||
|
iwdg_reset(); // kick the dog
|
||||||
|
led_tm1637_text(" dBa"); // display unit
|
||||||
|
sleep_ms(1000); // wait some time for the user to read
|
||||||
|
iwdg_reset(); // kick the dog
|
||||||
|
led_tm1637_number(sound_level_duration, false); // display duration
|
||||||
|
sleep_ms(1000); // wait some time for the user to read
|
||||||
|
iwdg_reset(); // kick the dog
|
||||||
|
led_tm1637_text(" sec"); // display unit
|
||||||
|
sleep_ms(1000); // wait some time for the user to read
|
||||||
|
iwdg_reset(); // kick the dog
|
||||||
|
led_tm1637_brightness(LED_TM1637_1DIV16); // set minimum brightness
|
||||||
|
led_tm1637_number(0, false); // show measurement
|
||||||
|
|
||||||
// setup terminal
|
// setup terminal
|
||||||
terminal_prefix = ""; // set default prefix
|
terminal_prefix = ""; // set default prefix
|
||||||
|
@ -411,11 +607,15 @@ void main(void)
|
||||||
// start main loop
|
// start main loop
|
||||||
bool action = false; // if an action has been performed don't go to sleep
|
bool action = false; // if an action has been performed don't go to sleep
|
||||||
button_flag = false; // reset button flag
|
button_flag = false; // reset button flag
|
||||||
|
uint32_t sound_level_valid = 0; // last time a valid value has been received
|
||||||
|
uint32_t sound_level_under = rtc_get_counter_val(); // last time the threshold has been exceeded
|
||||||
|
bool sound_level_invalid = false; // no value has been received for some time
|
||||||
|
bool sound_level_exceeded = false; // the level has exceeded the threshold longer than the duration
|
||||||
while (true) { // infinite loop
|
while (true) { // infinite loop
|
||||||
iwdg_reset(); // kick the dog
|
iwdg_reset(); // kick the dog
|
||||||
if (user_input_available) { // user input is available
|
if (user_input_available) { // user input is available
|
||||||
action = true; // action has been performed
|
action = true; // action has been performed
|
||||||
led_toggle(); // toggle LED
|
//led_toggle(); // show activity
|
||||||
char c = user_input_get(); // store receive character
|
char c = user_input_get(); // store receive character
|
||||||
terminal_send(c); // send received character to terminal
|
terminal_send(c); // send received character to terminal
|
||||||
}
|
}
|
||||||
|
@ -423,11 +623,57 @@ void main(void)
|
||||||
rtc_internal_tick_flag = false; // reset flag
|
rtc_internal_tick_flag = false; // reset flag
|
||||||
action = true; // action has been performed
|
action = true; // action has been performed
|
||||||
if (0 == (rtc_get_counter_val() % RTC_TICKS_SECOND)) { // one second has passed
|
if (0 == (rtc_get_counter_val() % RTC_TICKS_SECOND)) { // one second has passed
|
||||||
led_toggle(); // toggle LED (good to indicate if main function is stuck)
|
//led_toggle(); // heartbeat
|
||||||
uint32_t seconds = rtc_get_counter_val() / RTC_TICKS_SECOND; // get number of seconds
|
if (sound_level_exceeded) {
|
||||||
led_tm1637_time(seconds / 60, seconds % 60); // display time
|
led_tm1637_brightness(LED_TM1637_14DIV16); // set maximum brightness
|
||||||
|
if ((rtc_get_counter_val() / RTC_TICKS_SECOND) % 2) {
|
||||||
|
led_tm1637_text("too ");
|
||||||
|
} else {
|
||||||
|
led_tm1637_text("loud");
|
||||||
|
}
|
||||||
|
} else if (!sound_level_invalid && (((rtc_get_counter_val() - sound_level_valid) / RTC_TICKS_SECOND) >= 3)) { // no value received
|
||||||
|
sound_level_invalid = true; // remember the value is invalid
|
||||||
|
led_tm1637_number(0, false); // display empty number
|
||||||
|
led_tm1637_brightness(LED_TM1637_1DIV16); // set minimum brightness
|
||||||
|
} else if (!sound_level_exceeded && sound_level_valid > sound_level_under && (((rtc_get_counter_val() - sound_level_under) / RTC_TICKS_SECOND) >= sound_level_duration)) { // sound level exceeded for too long
|
||||||
|
sound_level_exceeded = true; // remember the value exceeded
|
||||||
|
led_on(); // light up reset switch
|
||||||
|
gpio_clear(GPIO_PORT(RELAY_PIN), GPIO_PIN(RELAY_PIN)); // enable relay
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (spp_rx_input_available) {
|
||||||
|
action = true; // action has been performed
|
||||||
|
//led_toggle(); // show activity
|
||||||
|
const char c = spp_rx_input_get(); // get the received data (also clears the flag)
|
||||||
|
if (!sound_level_exceeded) {
|
||||||
|
if (spp_input_i < LENGTH(spp_input_buffer) - 1) { // only store when there is enough space
|
||||||
|
spp_input_buffer[spp_input_i++] = c; // store received data
|
||||||
|
spp_input_buffer[spp_input_i] = '\0'; // end string
|
||||||
|
}
|
||||||
|
if ('\n' == c) { // end of line received
|
||||||
|
const uint8_t sound_level = parse_measurement(spp_input_buffer); // parse and display the received measurement
|
||||||
|
spp_input_i = 0; // reset buffer for next line
|
||||||
|
if (sound_level) {
|
||||||
|
sound_level_valid = rtc_get_counter_val(); // remember we got a valid value
|
||||||
|
if (sound_level_show) {
|
||||||
|
printf("%u dBa\n", sound_level);
|
||||||
|
}
|
||||||
|
led_tm1637_number(sound_level, false); // display number
|
||||||
|
if (sound_level_invalid) {
|
||||||
|
sound_level_invalid = false; // remember we got a value
|
||||||
|
sound_level_under = sound_level_valid; // remember the value is under the threshold
|
||||||
|
}
|
||||||
|
if (sound_level < sound_level_threshold) {
|
||||||
|
led_tm1637_brightness(LED_TM1637_1DIV16); // set minimum brightness
|
||||||
|
sound_level_under = sound_level_valid; // remember the value is under the threshold
|
||||||
|
} else {
|
||||||
|
led_tm1637_brightness(LED_TM1637_14DIV16); // set maximum brightness
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // end of line received
|
||||||
|
} // !sound_level_exceeded
|
||||||
|
} // spp_rx_input_available
|
||||||
if (action) { // go to sleep if nothing had to be done, else recheck for activity
|
if (action) { // go to sleep if nothing had to be done, else recheck for activity
|
||||||
action = false;
|
action = false;
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in New Issue