diff --git a/application.c b/application.c
index e1db3f6..9b0a2fb 100644
--- a/application.c
+++ b/application.c
@@ -12,8 +12,8 @@
* along with this program. If not, see .
*
*/
-/** STM32F1 application example
- * @file application.c
+/** STM32F1 application to strobe electricity
+ * @file
* @author King Kévin
* @date 2016-2018
*/
@@ -43,8 +43,9 @@
#include "usb_cdcacm.h" // USB CDC ACM utilities
#include "terminal.h" // handle the terminal interface
#include "menu.h" // menu utilities
+#include "ir_nec.h" // InfraRed NEC decoding utilities
-#define WATCHDOG_PERIOD 10000 /**< watchdog period in ms */
+#define WATCHDOG_PERIOD 20000 /**< watchdog period in ms */
/** @defgroup main_flags flag set in interrupts to be processed in main task
* @{
@@ -235,6 +236,94 @@ static void process_command(char* str)
}
}
+#define STROBE_PORT B /**< GPIO port to control strobe light */
+#define STROBE_PIN 6 /**< GPIO pin to control strobe light */
+#define STROBE_ON 0 /**< LED is on when pin is low (open-drain allows 5V on) */
+
+/* strobe animations (on + off times in ms) */
+/** single strobe */
+static const uint16_t strobe_single[] = {100, 0};
+/** double strobe */
+static const uint16_t strobe_double[] = {100, 200, 100, 0};
+
+/** switch strobe power on */
+static void strobe_on(void)
+{
+#if LED_ON
+ gpio_set(GPIO(STROBE_PORT), GPIO(STROBE_PIN));
+#else
+ gpio_clear(GPIO(STROBE_PORT), GPIO(STROBE_PIN));
+#endif
+}
+
+/** switch strobe power off */
+static void strobe_off(void)
+{
+#if STROBE_ON
+ gpio_clear(GPIO(STROBE_PORT), GPIO(STROBE_PIN));
+#else
+ gpio_set(GPIO(STROBE_PORT), GPIO(STROBE_PIN));
+#endif
+}
+
+/** toggle strobe power */
+static void strobe_toggle(void)
+{
+ gpio_toggle(GPIO(STROBE_PORT), GPIO(STROBE_PIN));
+}
+
+/** play strobe animation
+ * @param[in] animation on+off timings (in ms)
+ * @param[in] length animation length
+ */
+static void strobe_play(const uint16_t* animation, uint16_t length)
+{
+ for (uint16_t i = 0; i < length; i++) {
+ iwdg_reset(); // kick the dog
+ if (0 == animation[i]) { // skip animation
+ continue;
+ }
+ if (i % 2) { // odd index if encodes off duration
+ strobe_off();
+ } else {
+ strobe_on();
+ }
+ sleep_ms(animation[i]); // wait for set duration
+ }
+ strobe_off(); // switch off at the end
+}
+
+/** perform IR code related action
+ * @warning the codes need to be adjusted to your remote
+ * @param[in] code IR code
+ */
+static void ir_action(const struct ir_nec_code_t* code)
+{
+ if (code->repeat) { // don't handle long button press repeating the code
+ return;
+ }
+ if (0 != code->address) { // current remote uses this address
+ return;
+ }
+ switch (code->command) {
+ case 0x30: // power button
+ strobe_toggle();
+ printf("toggle strobe\n");
+ break;
+ case 0x88: // 1 button
+ strobe_play(strobe_single, LENGTH(strobe_single));
+ printf("strobe animation 1\n");
+ break;
+ case 0x48: // 2 button
+ strobe_play(strobe_double, LENGTH(strobe_double));
+ printf("strobe animation 2\n");
+ break;
+ default:
+ printf("unknown code\n");
+ break;
+ }
+}
+
/** program entry point
* this is the firmware function started by the micro-controller
*/
@@ -258,8 +347,17 @@ void main(void)
board_setup(); // setup board
uart_setup(); // setup USART (for printing)
- usb_cdcacm_setup(); // setup USB CDC ACM (for printing)
- printf("\nwelcome to the CuVoodoo STM32F1 example application\n"); // print welcome message
+ usb_cdcacm_setup(); // setup USB CDC ACM (for printing and DFU)
+ // setup strobe pin
+ rcc_periph_clock_enable(RCC_GPIO(STROBE_PORT)); // enable clock for GPIO port peripheral
+#if STROBE_ON
+ gpio_set_mode(GPIO(STROBE_PORT), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO(STROBE_PIN)); // set pin to output push-pull do drive strobe signal
+#else
+ gpio_set_mode(GPIO(STROBE_PORT), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO(STROBE_PIN)); // set pin to output open-drain do enable strobe
+#endif
+ strobe_off(); // switch off strobe per defaulf
+ ir_nec_setup(); // setup ID NEC code decoder
+ printf("\nwelcome to the CuVoodoo STM32F1 spark strober\n"); // print welcome message
#if !(DEBUG)
// show watchdog information
@@ -290,13 +388,13 @@ void main(void)
button_flag = false; // reset button flag
while (true) { // infinite loop
iwdg_reset(); // kick the dog
- while (user_input_available) { // user input is available
+ if (user_input_available) { // user input is available
action = true; // action has been performed
led_toggle(); // toggle LED
char c = user_input_get(); // store receive character
terminal_send(c); // send received character to terminal
}
- while (button_flag) { // user pressed button
+ if (button_flag) { // user pressed button
action = true; // action has been performed
printf("button pressed\n");
led_toggle(); // toggle LED
@@ -305,13 +403,22 @@ void main(void)
}
button_flag = false; // reset flag
}
- while (rtc_internal_tick_flag) { // the internal RTC ticked
+ if (rtc_internal_tick_flag) { // the internal RTC ticked
rtc_internal_tick_flag = false; // reset flag
action = true; // action has been performed
#if !defined(BLUE_PILL) // on the blue pill the LED is close to the 32.768 kHz oscillator and heavily influences it
- led_toggle(); // toggle LED (good to indicate if main function is stuck)
+ //led_toggle(); // toggle LED (good to indicate if main function is stuck)
#endif
}
+ if (ir_nec_code_received_flag) { // IR code received
+ ir_nec_code_received_flag = false; // reset flag
+ led_on(); // notify user we received a code
+ printf("IR NEC code received: addr=%+02x, cmd=%+02x%s\n", ir_nec_code_received.address, ir_nec_code_received.command, ir_nec_code_received.repeat ? " (repeat)" : "");
+ if (!ir_nec_code_received.repeat) { // ignore repeated codes
+ ir_action(&ir_nec_code_received); // handle IR code
+ }
+ led_off(); // notify user we received a code
+ }
if (action) { // go to sleep if nothing had to be done, else recheck for activity
action = false;
} else {