From d0d07b82f63a4f74375750abcbf0949346dc97dd Mon Sep 17 00:00:00 2001 From: true Date: Fri, 4 Aug 2023 02:13:47 -0700 Subject: [PATCH] main firmware: basic user UI, setting save / restore added Can now use the buttons to change programs, change active LED zones, change LED brightness and enter and exit programming mode. Exiting programming mode will save settings. Holding MODE upon boot will load defaults (though not overwrite them in EEPROM). Also added basic power management. If the badge is still for 15min, LEDs will go out. When LEDs are blank due to brightness off setting or timeout, they are turned off to save power. Moving badge, entering programming mode, changing the program, or changing brightness will enable the LEDs. --- badge_firmware/code/inc/btn.h | 23 ++- badge_firmware/code/inc/led_prog.h | 8 +- badge_firmware/code/inc/led_sk6x_spi.h | 8 + badge_firmware/code/inc/led_user.h | 5 + badge_firmware/code/inc/userconf.h | 36 ++++ badge_firmware/code/src/btn.c | 52 +++--- badge_firmware/code/src/led_prog.c | 227 ++++++++++++++++++++++--- badge_firmware/code/src/led_sk6x_spi.c | 74 +++++++- badge_firmware/code/src/led_user.c | 34 ++++ badge_firmware/code/src/main.c | 66 +++---- badge_firmware/code/src/userconf.c | 79 +++++++++ 11 files changed, 507 insertions(+), 105 deletions(-) create mode 100644 badge_firmware/code/inc/userconf.h create mode 100644 badge_firmware/code/src/userconf.c diff --git a/badge_firmware/code/inc/btn.h b/badge_firmware/code/inc/btn.h index d593bbb..5870596 100644 --- a/badge_firmware/code/inc/btn.h +++ b/badge_firmware/code/inc/btn.h @@ -17,15 +17,26 @@ #define BTN_PUSH (1 << 0) #define BTN_HELD (1 << 1) -#define BTN_RELEASE (1 << 2) +#define BTN_HELDRT (1 << 2) +#define BTN_RELEASE (1 << 3) #define BTN_PUSH_CB (1 << 4) #define BTN_HELD_CB (1 << 5) -#define BTN_RELEASE_CB (1 << 6) +#define BTN_HELDRT_CB (1 << 6) +#define BTN_RELEASE_CB (1 << 7) #define BTN_DEBOUNCE 11 // how many button ticks to wait before registering press #define BTN_MAX_HOLD (512*30) // longest reported / processed hold time (30s) -#define BTN_HOLD_SHIFT 6 // rshift value to get 1/16th sec hold time +#define BTN_HOLD_SHIFT 5 // rshift value to get 1/16th sec hold time + +#define BTN_HOLD_0_25S 4 +#define BTN_HOLD_0_50S 8 +#define BTN_HOLD_1_00S 16 +#define BTN_HOLD_1_50S 24 +#define BTN_HOLD_2_00S (16 * 2) +#define BTN_HOLD_3_00S (16 * 3) +#define BTN_HOLD_4_00S (16 * 4) +#define BTN_HOLD_5_00S (16 * 5) @@ -36,9 +47,9 @@ typedef struct Btn_t { uint16_t hold_retrig; // hold time retrigger threshold in button ticks, 0 disables uint16_t hold_rt_ctr; // hold retrigger counter - void (*push_cb)(); - void (*held_cb)(); - void (*release_cb)(); + void (*push_cb)(uint8_t); + void (*held_cb)(uint8_t); + void (*release_cb)(uint8_t); } Btn_t; /* diff --git a/badge_firmware/code/inc/led_prog.h b/badge_firmware/code/inc/led_prog.h index a9e385a..bbab581 100644 --- a/badge_firmware/code/inc/led_prog.h +++ b/badge_firmware/code/inc/led_prog.h @@ -10,12 +10,12 @@ -extern void (*ledprog)(); +void ledprog_default(); // set ledprog settings to defaults +void ledprog_change(); // change active ledprog idx +void ledprog_run(); - -void ledprog_default(); -void ledprog_change(); +void ledprog_btn(); // assign buttons to ledprog diff --git a/badge_firmware/code/inc/led_sk6x_spi.h b/badge_firmware/code/inc/led_sk6x_spi.h index 14b0365..7417a75 100644 --- a/badge_firmware/code/inc/led_sk6x_spi.h +++ b/badge_firmware/code/inc/led_sk6x_spi.h @@ -21,6 +21,11 @@ //#define SK6X_HI 0xc0 // 0b11000000, or 0.25/0.75uS on/off //#define SK6X_LO 0xfc // 0b11111100, or 0.75/0.25uS on/off +#define SK6X_ZONE_MAIN 0x01 +#define SK6X_ZONE_SIDE 0x02 +#define SK6X_ZONE_REAR 0x04 +#define SK6X_ZONE_ALL (SK6X_ZONE_MAIN | SK6X_ZONE_SIDE | SK6X_ZONE_REAR) + void led_sk6x_init(); @@ -31,6 +36,9 @@ void led_sk6x_set_all(uint8_t r, uint8_t g, uint8_t b); void led_sk6x_process(); void led_sk6x_update(); +void led_sk6x_zone_ena(uint8_t zone_mask); +void led_sk6x_brightness(uint8_t brightness); + #endif /* CODE_INC_LED_SK6X_SPI_H_ */ diff --git a/badge_firmware/code/inc/led_user.h b/badge_firmware/code/inc/led_user.h index f038ffc..e7d9f2d 100644 --- a/badge_firmware/code/inc/led_user.h +++ b/badge_firmware/code/inc/led_user.h @@ -10,4 +10,9 @@ +void userled_init(); +void userled_set(uint8_t brightness); + + + #endif /* CODE_INC_LED_USER_H_ */ diff --git a/badge_firmware/code/inc/userconf.h b/badge_firmware/code/inc/userconf.h new file mode 100644 index 0000000..64ad99f --- /dev/null +++ b/badge_firmware/code/inc/userconf.h @@ -0,0 +1,36 @@ +/* + * userconf.h + * + * Created on: Aug 3, 2023 + * Author: true + */ + +#ifndef CODE_INC_USERCONF_H_ +#define CODE_INC_USERCONF_H_ + + + +#define UCONF_MAGIC 0x1f + + + +typedef struct UserConf_t { + uint8_t magic; + uint8_t led_prog_idx; + uint8_t led_zone; + uint8_t led_bright; + uint8_t led[15][4]; +} UserConf_t; + + + +extern UserConf_t uconf; + + + +void uconf_save(); +void uconf_restore(uint8_t force_defaults); + + + +#endif /* CODE_INC_USERCONF_H_ */ diff --git a/badge_firmware/code/src/btn.c b/badge_firmware/code/src/btn.c index da2d082..17453ef 100644 --- a/badge_firmware/code/src/btn.c +++ b/badge_firmware/code/src/btn.c @@ -6,11 +6,17 @@ */ -static uint8_t mode = BTN_MODE_IDLE; - +#include +#include "hk32f030m.h" #include "btn.h" + + +// static uint8_t mode = BTN_MODE_IDLE; + + + Btn_t btn[BTN_COUNT] = {0}; @@ -28,6 +34,7 @@ static void btn_check(uint8_t idx, uint8_t state) } } else { btn[idx].held = 0; + btn[idx].hold_rt_ctr = 0; } } @@ -36,9 +43,9 @@ void btn_tick() uint8_t i; // increment hold - btn_check(0, BTN1); - btn_check(1, BTN2); - btn_check(2, BTN3); + btn_check(BTN_MODE, GPIOA->IDR & 0x4); + btn_check(BTN_PROG, GPIOA->IDR & 0x2); + btn_check(BTN_SET, GPIOA->IDR & 0x8); // process for (i = 0; i < BTN_COUNT; i++) { @@ -47,14 +54,21 @@ void btn_tick() // release first if (btn[i].held == 0) { // yes, released - btn[i].state = BTN_RELEASE; + btn[i].state |= BTN_RELEASE; // do we trigger hold? - } else if (btn[i].hold_time && (btn[i].held >> BTN_HOLD_SHIFT) == btn[i].hold_time) { + } else if (btn[i].hold_thresh && (btn[i].held >> BTN_HOLD_SHIFT) >= btn[i].hold_thresh) { // yes, held, but only set if we didn't already if (!(btn[i].state & BTN_HELD)) { btn[i].state = BTN_HELD; - btn[i].hold_rt_ctr = btn[i].hold_retrig; + } else if (btn[i].hold_retrig) { + // retrigger counter + btn[i].hold_rt_ctr++; + if (btn[i].hold_rt_ctr == btn[i].hold_retrig) { + // clear held callback + btn[i].state |= BTN_HELDRT; + btn[i].hold_rt_ctr = 0; + } } } } else { @@ -77,30 +91,28 @@ void btn_callback() if ((s & BTN_PUSH) && !(s & BTN_PUSH_CB)) { btn[i].state |= BTN_PUSH_CB; if (btn[i].push_cb) { - btn[i].push_cb(); - } - } - - if (btn[i].hold_retrig) { - if (btn[i].hold_rt_ctr) { - btn[i].hold_rt_ctr--; - } else { - btn[i].hold_rt_ctr = btn[i].hold_retrig; - btn[i].state &= ~(BTN_HELD_CB); + btn[i].push_cb(i); } } if ((s & BTN_HELD) && !(s & BTN_HELD_CB)) { btn[i].state |= BTN_HELD_CB; if (btn[i].held_cb) { - btn[i].held_cb(); + btn[i].held_cb(i); + } + } + + if ((s & BTN_HELDRT) && !(s & BTN_HELD_CB)) { + btn[i].state |= BTN_HELDRT_CB; + if (btn[i].held_cb) { + btn[i].held_cb(i); } } if ((s & BTN_RELEASE) && !(s & BTN_RELEASE_CB)) { btn[i].state |= BTN_RELEASE_CB; if (btn[i].release_cb) { - btn[i].release_cb(); + btn[i].release_cb(i); } } } diff --git a/badge_firmware/code/src/led_prog.c b/badge_firmware/code/src/led_prog.c index 5edace5..19b835b 100644 --- a/badge_firmware/code/src/led_prog.c +++ b/badge_firmware/code/src/led_prog.c @@ -8,9 +8,17 @@ #include + +#include "btn.h" #include "hsv2rgb.h" #include "led_sk6x_spi.h" +#include "led_user.h" #include "prng.h" +#include "userconf.h" + + + +#define LEDPROG_MAX_PROGRAMS 7 @@ -23,7 +31,6 @@ void ledprog5_flicker_all(); void ledprog6_ramper(); -static uint8_t settings[16][4]; const void (*led_prog_list[])() = { ledprog0_twinkle_white, @@ -35,38 +42,204 @@ const void (*led_prog_list[])() = { ledprog6_ramper }; -void (*ledprog)(); +static uint8_t led_prog_active = 0; static uint32_t work[4]; static uint8_t r, g, b; +static uint8_t prog_mode = 0; +static uint8_t prog_tmr = 0; +static uint8_t prog_led = 0; +static uint8_t prog_idx = 0; + +/* + * program pages: + * 1-4: 4 program bytes for active led program + */ + void ledprog_default() { - settings[3][2] = 2; - settings[3][3] = 30; + uconf.led[3][2] = 2; + uconf.led[3][3] = 30; - settings[4][1] = 248; - settings[4][2] = 170; - settings[4][3] = 16; + uconf.led[4][1] = 248; + uconf.led[4][2] = 170; + uconf.led[4][3] = 16; - settings[6][1] = 192; - settings[6][2] = 30; - settings[6][3] = 6; + uconf.led[6][1] = 192; + uconf.led[6][2] = 30; + uconf.led[6][3] = 6; } void ledprog_change(uint8_t idx) { uint8_t i; - ledprog = led_prog_list[idx]; + led_prog_active = idx; for (i = 0; i < 4; i++) { work[i] = 0; } } +void ledprog_btn_push_cb(uint8_t idx) +{ + if (!prog_mode) return; + + switch (idx) { + case BTN_MODE: { + + } + case BTN_SET: { + + } + } +} + +void ledprog_btn_held_cb(uint8_t idx) +{ + if (idx == BTN_PROG) { + prog_mode ^= 1; + prog_idx = prog_tmr = 0; + + // when leaving programming mode we need to commit settings to flash + if (!prog_mode) { + uconf.led_prog_idx = led_prog_active; + uconf_save(); + } + + return; + } + + if (prog_mode) { + switch (idx) { + case BTN_MODE: + case BTN_SET: { + ledprog_btn_push_cb(idx); + break; + } + } + + // allow retrigger + btn[idx].state &= ~(BTN_HELDRT | BTN_HELDRT_CB); + } else { + // do not retrigger on these + if (btn[idx].state & BTN_HELDRT_CB) return; + + switch (idx) { + case BTN_MODE: { // return to user's default program + ledprog_change(uconf.led_prog_idx); + led_sk6x_brightness(uconf.led_bright ? uconf.led_bright : 1); + break; + } + case BTN_SET: { // change active zones + uconf.led_zone++; + if (uconf.led_zone > 7) uconf.led_zone = 1; + led_sk6x_zone_ena(uconf.led_zone); + break; + } + } + } +} + +void ledprog_btn_release_cb(uint8_t idx) +{ + if (btn[idx].state & BTN_HELD) { + btn[idx].state = 0; + return; + } + + if (prog_mode) { + switch (idx) { + case BTN_PROG: { // change program variable page + prog_idx++; + if (prog_idx >= 4) prog_idx = 0; + break; + } + } + } else { + switch (idx) { + case BTN_MODE: { // change active program + led_prog_active++; + if (led_prog_active >= LEDPROG_MAX_PROGRAMS) led_prog_active = 0; + ledprog_change(led_prog_active); + + // increase brightness if we are dark + if (uconf.led_bright) { + break; + } + } + case BTN_PROG: { // change brightness + uconf.led_bright++; + if (uconf.led_bright > 5) uconf.led_bright = 0; + led_sk6x_brightness(uconf.led_bright); + break; + } + case BTN_SET: { // do nothing? + + } + } + } + + // clear any button state as button is now idle + btn[idx].state = 0; +} + +void ledprog_btn() +{ + btn[BTN_PROG].held_cb = ledprog_btn_held_cb; + btn[BTN_PROG].release_cb = ledprog_btn_release_cb; + btn[BTN_PROG].hold_thresh = BTN_HOLD_1_00S; + + btn[BTN_MODE].push_cb = ledprog_btn_push_cb; + btn[BTN_MODE].held_cb = ledprog_btn_held_cb; + btn[BTN_MODE].release_cb = ledprog_btn_release_cb; + btn[BTN_MODE].hold_thresh = BTN_HOLD_1_00S; + btn[BTN_MODE].hold_retrig = 10; + + btn[BTN_SET].push_cb = ledprog_btn_push_cb; + btn[BTN_SET].held_cb = ledprog_btn_held_cb; + btn[BTN_SET].release_cb = ledprog_btn_release_cb; + btn[BTN_SET].hold_thresh = BTN_HOLD_1_00S; + btn[BTN_SET].hold_retrig = 10; +} + +void ledprog_run() +{ + if (prog_mode) { + // we need to see the LEDs + if (!uconf.led_bright) { + uconf.led_bright++; + led_sk6x_brightness(uconf.led_bright); + } + + // 2 second LED flash timer + if (!prog_tmr) prog_led = prog_idx + 1; + + // flash LED to indicate the page we are programming + if (prog_led) { + switch (prog_tmr & 0x1f) { + case 0x00: { + userled_set(255); + break; + } + case 0x0a: { + userled_set(0); + prog_led--; + break; + } + } + } + + prog_tmr++; + } + + // always run a program + led_prog_list[led_prog_active](); +} + void ledprogi_twinkle(uint8_t r, uint8_t g, uint8_t b) { uint8_t x; @@ -82,7 +255,7 @@ void ledprogi_twinkle(uint8_t r, uint8_t g, uint8_t b) } /* - * settings: + * uconf.led: * 0 dwell * 1 threshold */ @@ -92,7 +265,7 @@ void ledprog0_twinkle_white() } /* - * settings: + * uconf.led: * 0 dwell * 1 threshold */ @@ -131,7 +304,7 @@ void ledprog1_twinkle_rgb_rand() /* - * settings: + * uconf.led: * 0 dwell * 1 threshold * 2 hue @@ -139,13 +312,13 @@ void ledprog1_twinkle_rgb_rand() */ void ledprog2_twinkle_rgb_set() { - hsv2rgb_8b(settings[2][2] * 6, 255, settings[2][3], &r, &g, &b); + hsv2rgb_8b(uconf.led[2][2] * 6, 255, uconf.led[2][3], &r, &g, &b); ledprogi_twinkle(r, g, b); } /* - * settings: + * uconf.led: * 0 dwell * 1 threshold * 2 speed @@ -159,7 +332,7 @@ void ledprog3_rainbow() uint8_t i; uint16_t w; - work[0] += (settings[3][2] * 6) + 1; + work[0] += (uconf.led[3][2] * 6) + 1; work[0] %= 1536; w = work[0]; @@ -167,7 +340,7 @@ void ledprog3_rainbow() hsv2rgb_8b(w, 255, 255, &r, &g, &b); led_sk6x_set(i, r, g, b); - w += (settings[3][3] * 6) + 1; + w += (uconf.led[3][3] * 6) + 1; w %= 1536; } } @@ -177,14 +350,14 @@ void ledprogi_flicker() uint16_t h; uint8_t x; - h = settings[4][2] * 6; + h = uconf.led[4][2] * 6; x = prng_get8(); - if (x > settings[4][1]) { + if (x > uconf.led[4][1]) { x = 255; } else { - x = settings[4][3]; + x = uconf.led[4][3]; } x &= ~0x07; @@ -194,7 +367,7 @@ void ledprogi_flicker() } /* - * settings: + * uconf.led: * 0 dwell * 1 threshold * 2 hue @@ -207,7 +380,7 @@ void ledprog4_flicker_same() } /* - * settings (uses ledprog4) + * uconf.led (uses ledprog4) * 0 dwell * 1 threshold * 2 hue @@ -224,7 +397,7 @@ void ledprog5_flicker_all() } /* - * settings + * uconf.led * 0 dwell * 1 speed * 2 hue @@ -245,11 +418,11 @@ void ledprog6_ramper() uint8_t fr; - h = settings[6][2] * 6; - fr = settings[6][3] & 0x3f; + h = uconf.led[6][2] * 6; + fr = uconf.led[6][3] & 0x3f; // speed -64 to -1, +1 to +64 - spd = (settings[6][1] >> 1) - 64; + spd = (uconf.led[6][1] >> 1) - 64; if (spd >= 0) spd++; work[0] += spd; work[0] &= 0xfff; diff --git a/badge_firmware/code/src/led_sk6x_spi.c b/badge_firmware/code/src/led_sk6x_spi.c index bf89137..b0ef52c 100644 --- a/badge_firmware/code/src/led_sk6x_spi.c +++ b/badge_firmware/code/src/led_sk6x_spi.c @@ -53,10 +53,13 @@ const uint8_t sk6x_map[8] = {0, 1, 2, 3, 4, 7, 6, 5}; -uint8_t sk6x_led[SK6X_LED_MAX_COUNT][3]; // G-R-B order -uint8_t sk6x_buf[SK6X_BUF_SIZE]; +static uint8_t sk6x_led[SK6X_LED_MAX_COUNT][3]; // G-R-B order +static uint8_t sk6x_buf[SK6X_BUF_SIZE]; -uint8_t sk6x_brightness = 3; +static uint8_t sk6x_brightness = 0; +static uint8_t sk6x_led_enabled = 0; + +static uint8_t sk6x_zone = SK6X_ZONE_ALL; @@ -80,14 +83,31 @@ __attribute__ ((long_call, section(".ramfunc"))) void led_sk6x_process() uint16_t n = 0; uint8_t b[8]; + uint8_t v; + j = 0; + // do nothing if LEDs are turned off + if (!sk6x_led_enabled) { + return; + } + // pack RGB values into 5-bits-per-bit format for (i = 0; i < SK6X_LED_MAX_COUNT; i++) { for (j = 0; j < 3; j++) { // pack values for next color uint8_t *p = b; - SK6X_FILL(sk6x_led[sk6x_map[i]][j] >> sk6x_brightness); + + v = sk6x_led[sk6x_map[i]][j] >> sk6x_brightness; + if (i <= 4) { + if (!(sk6x_zone & SK6X_ZONE_MAIN)) v = 0; + } else if (i <= 5) { + if (!(sk6x_zone & SK6X_ZONE_REAR)) v = 0; + } else { + if (!(sk6x_zone & SK6X_ZONE_SIDE)) v = 0; + } + + SK6X_FILL(v); // pack 8 bits into 5 bytes in final buffer sk6x_buf[n + 0] = (b[0] << 3) | (b[1] >> 2); @@ -102,11 +122,36 @@ __attribute__ ((long_call, section(".ramfunc"))) void led_sk6x_process() __attribute__ ((long_call, section(".ramfunc"))) void led_sk6x_update() { - // configure MOSI pin and bit depth - spi_mosi_sel(SPI_MOSI_LED); + // turn on / off LEDs based on brightness setting + if (sk6x_brightness >= 8) { + // leds should be OFF - // begin sending data + // if already off, we're done + if (!sk6x_led_enabled) return; + // otherwise, blank the LEDs + led_sk6x_process(); + } else { + // leds should be ON + if (!sk6x_led_enabled) { + // they aren't on, so turn them on + adxl345_set_intr_polarity(ADXL345_INTR_ACTIVE_LO); + sk6x_led_enabled = 1; + } + } + + // configure MOSI pin and bit depth, then send LED data + spi_mosi_sel(SPI_MOSI_LED); spi_xfer(sk6x_buf, 0, sizeof(sk6x_buf), SPI_NO_CALLBACK); + + // turn off LEDs based on brightness setting + if (sk6x_brightness >= 8) { + // leds should be OFF + if (sk6x_led_enabled) { + // LEDs should be blanked, so we can turn them off now + adxl345_set_intr_polarity(ADXL345_INTR_ACTIVE_HI); + sk6x_led_enabled = 0; + } + } } __attribute__ ((long_call, section(".ramfunc"))) void led_sk6x_set(uint8_t index, uint8_t r, uint8_t g, uint8_t b) @@ -144,3 +189,18 @@ void led_sk6x_cb() { // there is nothing to handle after updating LEDs } + +void led_sk6x_zone_ena(uint8_t zone_mask) +{ + sk6x_zone = zone_mask & SK6X_ZONE_ALL; +} + +void led_sk6x_brightness(uint8_t brightness) +{ + if (brightness >= 5) brightness = 5; + + if (brightness == 0) brightness = 8; + else brightness = 5 - brightness; + + sk6x_brightness = brightness; +} diff --git a/badge_firmware/code/src/led_user.c b/badge_firmware/code/src/led_user.c index beb701a..7a60055 100644 --- a/badge_firmware/code/src/led_user.c +++ b/badge_firmware/code/src/led_user.c @@ -6,3 +6,37 @@ */ +#include "hk32f030m.h" +#include + + + +#define USERLED_IPORT GPIOC // i2c port/pin +#define USERLED_IPIN 6 + +#define USERLED_LPORT GPIOD // led port/pin +#define USERLED_LPIN 7 + + + +void userled_init() +{ + +} + +void userled_set(uint8_t brightness) +{ + if (!brightness) { + USERLED_IPORT->MODER &= ~(0x3 << (USERLED_IPIN * 2)); + USERLED_IPORT->MODER |= (GPIO_Mode_IN << (USERLED_IPIN * 2)); + + USERLED_LPORT->BRR = (1 << USERLED_LPIN); + } else { + // set i2c port low while LED is lit + USERLED_IPORT->MODER &= ~(0x3 << (USERLED_IPIN * 2)); + USERLED_IPORT->MODER |= (GPIO_Mode_OUT << (USERLED_IPIN * 2)); + USERLED_IPORT->BRR = (1 << USERLED_IPIN); + + USERLED_LPORT->BSRR = (1 << USERLED_LPIN); + } +} diff --git a/badge_firmware/code/src/main.c b/badge_firmware/code/src/main.c index c459435..3588ba7 100644 --- a/badge_firmware/code/src/main.c +++ b/badge_firmware/code/src/main.c @@ -19,18 +19,23 @@ #include "prng.h" #include "spi.h" #include "timer.h" +#include "userconf.h" #define GPIO_RCC_AHB_GPIO_ALL RCC_AHBPeriph_GPIOA | RCC_AHBPeriph_GPIOB | \ RCC_AHBPeriph_GPIOC | RCC_AHBPeriph_GPIOD +#define NO_MOVE_SLEEP_TIME (15 * 60) * 32 + static uint32_t uptime = 0; // uptime in seconds volatile uint16_t cnt = 0; // 1/1000 second tick static uint16_t cnt2 = 0; // low priority loop check +static uint32_t no_move_ticks; // keep track of how long we are still + static void gpio_init() @@ -150,17 +155,18 @@ int main(void) adxl345_init(); adxl345_tick(); + // load user config, unless SET button is held, in which case we restore defaults + uconf_restore(!(GPIOA->IDR & (1 << 3))); + // configure prng tinymt32_init(&tinymt32_s, (adxl.x << 16) | (adxl.y << 8) | adxl.z); // configure addressable LEDs led_sk6x_init(); - ledprog_default(); - ledprog_change(6); - // configure user input btn_init(); + ledprog_btn(); // configure mainline timer #ifdef DEBUG @@ -183,7 +189,7 @@ int main(void) // led programs (128Hz) if ((cnt2 & 0x7) == 0) { - if (ledprog) ledprog(); + ledprog_run(); // stuff next LED bits led_sk6x_process(); @@ -210,44 +216,22 @@ __attribute__ ((long_call, section(".ramfunc"))) void TIM6_IRQHandler() btn_tick(); } - // temp: run LED program - /* - static uint8_t v[3]; - static uint8_t x = 0; - if (!(cnt % 4)) { - v[x]++; - if (!v[x]) { - x++; - if (x >= 3) x = 0; - } - } - */ - - // run next LED program - - /* - uint8_t w[2]; - w[0] = v[0] >> 2; - w[1] = v[1] >> 2; - w[2] = v[2] >> 2; - led_sk6x_set(0, w[0], w[1], w[2]); - led_sk6x_set(1, w[1], w[2], w[0]); - led_sk6x_set(2, w[2], w[0], w[1]); - led_sk6x_set(3, w[1], w[2], w[0]); - led_sk6x_set(4, w[0], w[1], w[2]); - led_sk6x_set(5, w[0], w[1], w[2]); - led_sk6x_set(6, w[1], w[2], w[0]); - led_sk6x_set(7, w[2], w[0], w[1]); - */ - /* - for (int i = 1; i < 8; i++) { - led_sk6x_set(i, v[0] + (i * 32), v[1] + (i * 32), v[2] + (i * 32)); - } - */ - - // accelerometer: tick - if ((cnt & 0x3f) == 0x3f) { + // accelerometer: tick 32Hz + if ((cnt & 0x1f) == 0x1e) { adxl345_tick(); + + // should we sleep? + // todo: make this interrupt driven, and tune required accel value + if (adxl345_movement() < 6) { + if (no_move_ticks >= NO_MOVE_SLEEP_TIME) { + led_sk6x_brightness(0); + } else no_move_ticks++; + } else { + if (no_move_ticks >= NO_MOVE_SLEEP_TIME) { + led_sk6x_brightness(uconf.led_bright); + } + no_move_ticks = 0; + } } diff --git a/badge_firmware/code/src/userconf.c b/badge_firmware/code/src/userconf.c new file mode 100644 index 0000000..0012955 --- /dev/null +++ b/badge_firmware/code/src/userconf.c @@ -0,0 +1,79 @@ +/* + * userconf.c + * + * Created on: Aug 3, 2023 + * Author: true + */ + + +#include +#include + +#include "hk32f030m.h" + +#include "userconf.h" + +#include "led_prog.h" +#include "led_sk6x_spi.h" + + + +#define EEPROM_BASE_ADDR 0x0c000000; + + + +UserConf_t uconf = {0}; + + + +void uconf_save() +{ + uint8_t i; + UserConf_t usave; + + uint8_t *eeprom = (uint8_t *)EEPROM_BASE_ADDR; + uint8_t *u8save = (uint8_t *)&usave; + + memcpy((void *)&usave, (void *)&uconf, sizeof(uconf)); + + // never save brightness as minimum value + if (!usave.led_bright) usave.led_bright++; + + // commit bytes to eeprom only if they differ + for (i = 0; i < sizeof(uconf); i++) { + if (*eeprom != *u8save) { + // erase byte + EEPROM_EraseByte((uint32_t)eeprom); + + // write new byte + EEPROM_ProgramByte((uint32_t)eeprom, *u8save); + } + + eeprom++; + u8save++; + } +} + +void uconf_restore(uint8_t force_defaults) +{ + uint8_t *eeprom = (uint8_t *)EEPROM_BASE_ADDR; + + if ((*eeprom != 0x1f) || force_defaults) { + // nothing to restore. load defaults instead + uconf.magic = UCONF_MAGIC; + + uconf.led_prog_idx = 3; // rainbow + uconf.led_bright = 3; // 50% brightness + uconf.led_zone = 7; // all zones active + + ledprog_default(); + } else { + // copy from eeprom to uconf + memcpy((void *)&uconf, (void *)eeprom, sizeof(uconf)); + } + + // set settings from user config + ledprog_change(uconf.led_prog_idx); + led_sk6x_zone_ena(uconf.led_zone); + led_sk6x_brightness(uconf.led_bright); +}