fix pepper programs, store / retrieve user config from flash
fix issues with button handler. pepper programs are now selectable in sequence with the left pepper hat button.
This commit is contained in:
parent
a6966fc32f
commit
6f9444ab5c
|
@ -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
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* Author: true
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <ch32v20x.h>
|
||||
|
||||
#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
|
||||
// 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;
|
||||
valid = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
|
||||
|
||||
extern void (*ledprog_rgb[8])(uint8_t, uint8_t);
|
||||
extern void (*ledprog_rgb[8])(uint8_t);
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -4,8 +4,11 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
#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) {
|
||||
|
||||
|
|
Loading…
Reference in New Issue