diff --git a/firmware/user/src/btn.c b/firmware/user/src/btn.c index e29ca35..3eb7f77 100644 --- a/firmware/user/src/btn.c +++ b/firmware/user/src/btn.c @@ -17,7 +17,13 @@ struct Btn btn[BTN_COUNT] = {0}; void btn_init() { + uint8_t i; + touch_init(); + + for (i = 0; i < BTN_COUNT; i++) { + btn[i]._mask = BTN_RELEASE; + } } void btn_poll() @@ -29,16 +35,16 @@ void btn_poll() ignore = btn[i]._mask & BTN_IGNORE; if (touch_read_pushed(i)) { - // is pushed - if (btn[i]._count < BTN_DEBOUNCE) continue; - // hold counter if (btn[i]._count < 0xffff) btn[i]._count++; + // pushed long enough? + if (btn[i]._count < BTN_DEBOUNCE) continue; + // first push? - if (!btn[i]._mask & BTN_PUSH) { - btn[i]._mask = BTN_PUSH; - if (btn[i].cb_push) { + if (!(btn[i]._mask & BTN_PUSH)) { + btn[i]._mask = BTN_PUSH | ignore; + if (btn[i].cb_push && !ignore) { btn[i].cb_push(i); btn[i]._mask |= (BTN_PUSH << 4); } @@ -46,7 +52,7 @@ void btn_poll() // held to count limit // if button is not repeatable, do not retrigger - if ((btn[i]._mask && BTN_HOLD) && !btn[i].repeat) continue; + if ((btn[i]._mask & BTN_HOLD) && !btn[i].repeat) continue; btn[i]._mask |= BTN_HOLD; // call callback only if not in ignore state @@ -56,11 +62,14 @@ void btn_poll() } // apply repeat rate to count - btn[i]._count -= btn[i].repeat; + if (btn[i].repeat > btn[i]._count) { + btn[i]._count = 0; + } else btn[i]._count -= btn[i].repeat; } } else { // is not pushed - if (!btn[i]._mask & BTN_RELEASE) { + if (!(btn[i]._mask & BTN_RELEASE)) { + // note: release will remove ignore status btn[i]._mask = BTN_RELEASE; btn[i]._count = 0; // call callback only if not in ignore state diff --git a/firmware/user/src/config.c b/firmware/user/src/config.c index 472468c..b66d48d 100644 --- a/firmware/user/src/config.c +++ b/firmware/user/src/config.c @@ -5,6 +5,7 @@ * Author: true */ +#include #include #include "config.h" @@ -42,11 +43,13 @@ uint32_t chip_get_flash_size() } } -static uint32_t * calc_address() +static uint32_t calc_address() { - return (uint32_t *)(FLASH_BASE + chip_get_flash_size()) - (CONF_FLASH_PAGE_SIZE * CONF_FLASH_PAGES); + uint32_t calc = (FLASH_BASE + chip_get_flash_size()) - (CONF_FLASH_PAGE_SIZE * CONF_FLASH_PAGES); + return calc; } +/* static void read_page_from_flash(uint8_t page, uint32_t *data, uint16_t len) { uint32_t *addr = calc_address(); @@ -60,25 +63,26 @@ static void read_page_from_flash(uint8_t page, uint32_t *data, uint16_t len) // read the data flash_read(addr, data, len); } +*/ static void write_page_to_flash(uint8_t page, uint32_t *data, uint16_t len) { len = (uint16_t)len; - uint32_t *addr = calc_address() + (page * CONF_FLASH_PAGE_SIZE); + uint32_t addr = calc_address() + (page * CONF_FLASH_PAGE_SIZE); // write the data // note we don't pass any length. we'll just read whatever garbage // is in RAM after our config and write it to flash. lol - flash_write256(addr, data); + flash_write256((uint32_t *)addr, data); } -static uint16_t checksum() +static uint16_t checksum(struct UserConf *conf) { uint16_t i; uint16_t sum = 0; - uint8_t *uc = (uint8_t *)&userconf; + uint8_t *uc = (uint8_t *)conf; // calculate checksum for (i = 0; i < sizeof(userconf) - 6; i++) { @@ -90,30 +94,39 @@ static uint16_t checksum() void userconf_load() { - uint8_t valid = 0; + uint8_t i; + + uint32_t ver_highest = 0; uint8_t page = CONF_FLASH_PAGES; + uint32_t addr; + struct UserConf *flash; - // read pages backward until we get non-empty flash - while (page) { - read_page_from_flash(--page, (uint32_t *)&userconf, sizeof(userconf)/4); - if (userconf.checkval == CHECKVAL) { - if (userconf.checksum == checksum()) { - // data appears to be valid... use it - active_page = page; - valid = 1; + // read pages and see if we can find our data + while (page--) { + addr = calc_address() + (page * CONF_FLASH_PAGE_SIZE); + flash = (struct UserConf *)addr; + if (flash->checkval == CHECKVAL) { + if (flash->checksum == checksum(flash)) { + if (ver_highest < flash->version) { + ver_highest = flash->version; + active_page = page; + } } } } - if (!valid) { + if (!ver_highest) { // config is invalid; reset to default userconf.version = 0; - userconf.checksum = checksum(); - userconf.checkval = CHECKVAL; - - // default program connfigs + // default program configs + for (i = 0; i < 8; i++) { + userconf.pep_conf[i][0] = 0; + userconf.pep_conf[i][1] = 0; + userconf.pep_conf[i][2] = 0; + userconf.pep_conf[i][3] = 0; + } // program 0: flashing userconf.pep_conf[0][0] = 0x80; // brightness @@ -122,19 +135,25 @@ void userconf_load() // program 2: loops userconf.pep_conf[2][0] = 0xc0; // brightness userconf.pep_conf[2][1] = 0; // looping rate - userconf.pep_conf[2][3] = 3; // decay rate + userconf.pep_conf[2][3] = 1; // decay rate // program 4: alternating userconf.pep_conf[4][0] = 0x80; // brightness - userconf.pep_conf[4][1] = 8; // flash rate + userconf.pep_conf[4][1] = 12; // flash rate userconf.pep_conf[4][3] = 0x0b; // lower brightness on alternate + + userconf.checksum = checksum(&userconf); + userconf.checkval = CHECKVAL; + } else { + memcpy(&userconf, (uint8_t *)(calc_address() + (active_page * 256)), sizeof(userconf)); } } void userconf_save() { + // we can only save ~4 billion times userconf.version++; - userconf.checksum = checksum(); + userconf.checksum = checksum(&userconf); userconf.checkval = CHECKVAL; // determine page to write @@ -145,6 +164,5 @@ void userconf_save() // nothing is mentioned in the datasheet nor reference manual // about repeated writes. so to be safe, each page gets // written to once per erase. - write_page_to_flash(active_page, (uint32_t *)&userconf, sizeof(userconf)/4); } diff --git a/firmware/user/src/led.c b/firmware/user/src/led.c index 4167c47..e40025b 100644 --- a/firmware/user/src/led.c +++ b/firmware/user/src/led.c @@ -67,6 +67,15 @@ void led_init() TIM_TimeBaseInitTypeDef timer ={0}; TIM_OCInitTypeDef pwm = {0}; + uint8_t i; + + + // reset LED values + for (i = 0; i < FL3729_SW_COUNT * FL3729_CS_COUNT; i++) { + led.all[i] = 0; + } + rgb[0] = rgb[1] = rgb[2] = 0; + // configure matrix is31fl3729_init(FL3729_ADDR, diff --git a/firmware/user/src/ledprog_pep.c b/firmware/user/src/ledprog_pep.c index 8e1fc04..b9988c1 100644 --- a/firmware/user/src/ledprog_pep.c +++ b/firmware/user/src/ledprog_pep.c @@ -195,17 +195,53 @@ static void pep_2_loops(uint8_t tick) * segment, upper and lower, turns on * after both segments are on the separator goes off */ +static uint8_t flicker_count[2]; +static uint8_t flicker_delay[2]; +static uint8_t flicker_timer[2]; + static void pep_3_neon_sign(uint8_t tick) { uint8_t i; + uint16_t rnd; + uint8_t target; + + if (tick & 4) { + rnd = prng_get8(); + if (rnd >= 0xfc) { + // do a flicker + target = rnd & 1; + + flicker_count[target] = prng_scale16(1, 4) << 1; + flicker_delay[target] = prng_scale16(12, 240); + + if (rnd & 2) { + flicker_count[target ^ 1] = flicker_count[target]; + flicker_delay[target ^ 1] = flicker_delay[target]; + } + } + } + + + // todo: implement flickering on/off // like a flourescent tube warming up or failing + for (i = 0; i < 2; i++) { + if (flicker_count[i]) { + if (flicker_timer[i]) { + flicker_timer[i]--; + } else { + flicker_count[i]--; + flicker_timer[i] = flicker_delay[i]; + } + } + } + for (i = 0; i < LED_PEP_COUNT; i++) { - led.section.pep[i] = (tick & 2) ? 0x40 : 16; + led.section.pep[i] = flicker_count[0] & 1 ? 0 : 0x80; } for (i = 0; i < LED_HAT_COUNT; i++) { - led.section.hat[i] = (tick & 2) ? 0x80 : 24; + led.section.hat[i] = flicker_count[1] & 1 ? 0 : 0x60; } led_matrix_is_updated(); @@ -257,9 +293,10 @@ static const uint8_t nom_map[5][2] = { {14, 21}, {12, 23}, { 9, 24}, - { 5, 27}, - { 2, 29} + { 7, 27}, + { 3, 28} }; +uint16_t nom_timeout = 0; static void pep_5_nom(uint8_t tick) { @@ -269,13 +306,21 @@ static void pep_5_nom(uint8_t tick) switch (pep_work[0]) { case 0: case 2: { // wait a while - if (!pep_work[2]) { + if (!nom_timeout) { // just got here; set a new random timeout - pep_work[2] = 0xff - (prng_get8() >> 2); + nom_timeout = 0x3ff - prng_get8(); + // also set the pepper to be on + for (i = LED_PEP_NOTOP; i < LED_PEP_COUNT; i++) { + led.section.pep[i] = 0x80; + } + for (i = 0; i < LED_HAT_COUNT; i++) { + led.section.hat[i] = 0x60; + } + led_matrix_is_updated(); } else { // wait around for a little while - pep_work[2]--; - if (!pep_work[2]) { + nom_timeout--; + if (!nom_timeout) { // done here pep_work[1] = 0; pep_work[0]++; @@ -286,9 +331,28 @@ static void pep_5_nom(uint8_t tick) break; } - case 1: { // eat the pepper + case 1: { // regen the pepper + if (led.section.pep[pep_work[1]] >= (0x80 - 4)) { + // next segment + pep_work[1]++; + if (pep_work[1] > (LED_PEP_NOTOP - pep_work[1])) { + // we're done regenerating + pep_work[0]++; + } + } else { + led.section.pep[pep_work[1]] += 4; + if (pep_work[1]) { + led.section.pep[LED_PEP_NOTOP - pep_work[1]] = led.section.pep[pep_work[1]]; + } + led_matrix_is_updated(); + } + + break; + } + + case 3: { // eat the pepper // eat at about one bite per second - if ((tick & 0x3f) != 0) break; + if ((tick & 0x7f) != 0) break; start = 0; @@ -321,26 +385,7 @@ static void pep_5_nom(uint8_t tick) pep_work[1]++; - if (pep_work[1] > 6) pep_work[0]++; - - break; - } - - case 3: { // regen the pepper - if (led.section.pep[pep_work[1]] >= (0x80 - 4)) { - // next segment - pep_work[1]++; - if (pep_work[1] > (LED_PEP_NOTOP - pep_work[1])) { - // we're done regenerating - pep_work[0] = 0; - } - } else { - led.section.pep[pep_work[1]] += 4; - if (pep_work[1]) { - led.section.pep[LED_PEP_NOTOP - pep_work[1]] = led.section.pep[pep_work[1]]; - } - led_matrix_is_updated(); - } + if (pep_work[1] > 6) pep_work[0] = 0; break; } @@ -413,6 +458,7 @@ void ledprog_pep_init() } // per-program initialization + nom_timeout = 0; // there is none on this badge } diff --git a/firmware/user/src/ledprog_rgb.c b/firmware/user/src/ledprog_rgb.c index f98aa62..6456188 100644 --- a/firmware/user/src/ledprog_rgb.c +++ b/firmware/user/src/ledprog_rgb.c @@ -15,11 +15,18 @@ static uint16_t rgb_work[4]; +/* + * + */ +static void rgb_0_nothing(uint8_t tick) +{ + rgb[0] = rgb[1] = rgb[2] = 0; +} + /* * rainbow puke */ - -static void rgb_0_rainbow(uint8_t tick) +static void rgb_1_rainbow(uint8_t tick) { } @@ -27,7 +34,7 @@ static void rgb_0_rainbow(uint8_t tick) /* * static color with bright flickers */ -static void rgb_1_flicker(uint8_t tick) +static void rgb_2_candle(uint8_t tick) { } @@ -35,17 +42,18 @@ static void rgb_1_flicker(uint8_t tick) /* * alternate between two colors */ -static void rgb_2_alternate(uint8_t tick) +static void rgb_3_alternate(uint8_t tick) { } -const void (*ledprog_rgb[4])(uint8_t) = { - (const void (*)(uint8_t))rgb_0_rainbow, - (const void (*)(uint8_t))rgb_1_flicker, - (const void (*)(uint8_t))rgb_2_alternate +void (*ledprog_rgb[4])(uint8_t) = { + rgb_0_nothing, + rgb_1_rainbow, + rgb_2_candle, + rgb_3_alternate }; diff --git a/firmware/user/src/ledprog_rgb.h b/firmware/user/src/ledprog_rgb.h index 3792391..24f2c0c 100644 --- a/firmware/user/src/ledprog_rgb.h +++ b/firmware/user/src/ledprog_rgb.h @@ -14,7 +14,7 @@ -extern void (*ledprog_rgb[8])(uint8_t, uint8_t); +extern void (*ledprog_rgb[8])(uint8_t); diff --git a/firmware/user/src/ui.c b/firmware/user/src/ui.c index e17b5f6..026012a 100644 --- a/firmware/user/src/ui.c +++ b/firmware/user/src/ui.c @@ -4,8 +4,11 @@ #include +#include "ui.h" + #include "adc.h" #include "btn.h" +#include "config.h" #include "led.h" #include "ledprog_pep.h" #include "ledprog_rgb.h" @@ -16,11 +19,13 @@ #define MODE_PROGRAM 1 #define MODE_PARAMETER 2 -#define UI_CONF_SAVE_TIMEOUT 160 +#define UI_CONF_SAVE_TIMEOUT 512 #define UI_PROG_RUNTIME_MIN (128*15) // 15 seconds #define UI_PROG_RUNTIME_MAX (128*120) // 120 seconds +#define PROG_REPEAT 0x80 + static const uint8_t led_gc_map[] = { @@ -35,6 +40,8 @@ static const uint8_t led_gc_map[] = { static uint8_t mode = MODE_RUN; static uint8_t tick = 0; +static uint16_t save_delay = 0; + void ui_btn_push_cb(uint8_t idx) @@ -44,33 +51,61 @@ void ui_btn_push_cb(uint8_t idx) void ui_btn_hold_cb(uint8_t idx) { - + switch (idx) { + case 0: { // left pepper hat + userconf.pep_prog_ena_map ^= PROG_REPEAT; + break; + } + case 1: { // right pepper hat + userconf.rgb_prog_ena_map ^= PROG_REPEAT; + break; + } + } } void ui_btn_release_cb(uint8_t idx) { + uint8_t update; + switch (idx) { + case 0: { // left pepper hat + update = userconf.pep_prog_ena_map & ~(PROG_REPEAT); + update++; + if (update > 5) update = 0; + userconf.pep_prog_ena_map = update | (userconf.pep_prog_ena_map & PROG_REPEAT); + ledprog_pep_init(); + break; + } + case 1: { // right pepper hat + update = userconf.rgb_prog_ena_map & ~(PROG_REPEAT); + update++; + if (update > 3) update = 0; + userconf.rgb_prog_ena_map = update | (userconf.rgb_prog_ena_map & PROG_REPEAT); + ledprog_rgb_init(); + break; + } + } + + save_delay = UI_CONF_SAVE_TIMEOUT; } void ui_init() { - btn[0].hold = 330 >> 1; + btn[0].hold = 1200 >> 1; btn[0].repeat = 0; // (1000 / 20) >> 1; btn[0].cb_push = ui_btn_push_cb; btn[0].cb_hold = ui_btn_hold_cb; btn[0].cb_release = ui_btn_release_cb; - btn[1].hold = 330 >> 1; + btn[1].hold = 1200 >> 1; btn[1].repeat = 0; btn[1].cb_push = ui_btn_push_cb; btn[1].cb_hold = ui_btn_hold_cb; btn[1].cb_release = ui_btn_release_cb; } -uint8_t tmp; -volatile uint8_t prog_run = 5; void ui_render() { @@ -78,8 +113,27 @@ void ui_render() tick++; + uint8_t prog_pep_idx = userconf.pep_prog_ena_map & ~(PROG_REPEAT); + uint8_t prog_rgb_idx = userconf.rgb_prog_ena_map & ~(PROG_REPEAT); + switch (mode) { case MODE_RUN: { + // run programs + if (ledprog_pep[prog_pep_idx]) { + ledprog_pep[prog_pep_idx](tick); + } + if (ledprog_rgb[prog_rgb_idx]) { + ledprog_rgb[prog_rgb_idx](tick); + } + + // check flash save + if (save_delay) { + save_delay--; + if (!save_delay) { + userconf_save(); + } + } + break; } @@ -107,7 +161,7 @@ void ui_render() // temporary: testing - ledprog_pep[prog_run](tick); + // ledprog_pep[prog_run](tick); /* if ((tick & 3) == 3) {