dc32-peppercon9-addon/firmware/user/src/ledprog_pep.c

386 lines
8.3 KiB
C
Raw Normal View History

/*
* Created on: Jul 29, 2024
*/
#include <stdint.h>
#include "config.h"
#include "led.h"
#include "lis2dw.h"
#include "rand.h"
enum {
PEP_0, PEP_1, PEP_2, PEP_3,
PEP_4, PEP_5, PEP_6, PEP_7
};
static uint16_t pep_rnd;
static uint8_t pep_work[4];
/*
* my little pepper is flashing you
* can be instant (all on/off) or fading in/out
* todo: implement fading mode
* if flash rate is 0, then just stay solid
*
* work global:
* 0: flash timeout
* 1: flash state
* 2: fade timeout
* 3: fade state
*/
#define PEP_0_CONF_BRIGHTNESS 0
#define PEP_0_CONF_FLASH_RATE 1
#define PEP_0_CONF_FADE_ENA 2
#define PEP_0_CONF_FADE_RATE 3
static void pep_0_flash(uint8_t tick)
{
uint8_t i;
uint16_t out = userconf.pep_conf[PEP_0][PEP_0_CONF_BRIGHTNESS] ^ 0xff;
uint8_t flash = userconf.pep_conf[PEP_0][PEP_0_CONF_FLASH_RATE];
if (!flash) {
// just force solid on
pep_work[0] = pep_work[1] = 0;
flash = 1;
}
if (!pep_work[0]) {
pep_work[1] ^= 0x1;
if (pep_work[1] & 1) {
for (i = 0; i < LED_PEP_COUNT; i++) {
led.pep[i] = out;
}
for (i = 0; i < LED_HAT_COUNT; i++) {
led.hat[i] = out;
}
} else {
for (i = 0; i < LED_PEP_COUNT; i++) {
led.pep[i] = 0;
}
for (i = 0; i < LED_HAT_COUNT; i++) {
led.hat[i] = 0;
}
}
led_matrix_is_updated();
pep_work[0] = flash;
}
pep_work[0]--;
}
/*
* pepper is lit with random slightly varying intensity
*/
static void pep_1_sizzle(uint8_t tick)
{
uint8_t i;
uint8_t trig;
uint16_t rnd;
uint32_t rnd2;
trig = prng_get8();
rnd = prng_get8();
rnd2 = prng_get32();
// are we going to spike an LED?
trig = (trig > 0xf2) ? 1 : 0;
if (trig) {
// which LED?
rnd *= LED_PEP_NOTOP;
rnd >>= 8;
}
// do some sizzles
for (i = 0; i < LED_PEP_NOTOP; i++) {
if (trig && (rnd == i)) {
// go bright on this LED
led.pep[i] = 200;
} else {
if (led.pep[i] < 48) led.pep[i]++;
else if (led.pep[i] > 64) led.pep[i]--;
else {
if (rnd2 & 1) led.pep[i]++;
else led.pep[i]--;
}
rnd2 >>= 1;
}
}
// the hat just gets lit normally
for (i = 0; i < LED_HAT_COUNT; i++) {
led.hat[i] = 200;
}
}
/*
* trail chase around the pepper
* pepper is on slightly dim at all times
*
* no user config at this time
*
* work global:
* 0: loop state
*/
static void pep_2_loops(uint8_t tick)
{
uint8_t i;
uint16_t top, bot;
pep_work[0]++;
top = pep_work[0] * LED_PEP_COUNT;
top >>= 8;
bot = pep_work[0] * LED_HAT_COUNT;
bot >>= 8;
for (i = 0; i < LED_PEP_COUNT; i++) {
if (i == bot) led.pep[i] = 255;
else if (led.pep[i]) led.pep[i]--;
}
for (i = 0; i < LED_HAT_COUNT; i++) {
if (i == top) led.hat[i] = 255;
else if (led.hat[i]) led.hat[i]--;
}
}
/*
* pepper is a "sign" that flickers on and off
* sometimes the entire sign goes off, then each
* segment, upper and lower, turns on
* after both segments are on the separator goes off
*/
static void pep_3_neon_sign(uint8_t tick)
{
uint8_t i;
// todo: implement flickering on/off
for (i = 0; i < LED_PEP_COUNT; i++) {
led.pep[i] = (tick & 1) ? 255 : 200;
}
for (i = 0; i < LED_HAT_COUNT; i++) {
led.hat[i] = (tick & 1) ? 255 : 200;
}
led_matrix_is_updated();
}
/*
* pepper hat and pepper alternate
* can be a nice fade or can be immediate
*/
#define PEP_4_CONF_BRIGHTNESS 0
#define PEP_4_CONF_FLASH_RATE 1
#define PEP_4_CONF_LOW_BRITE 2
static void pep_4_alternate(uint8_t tick)
{
uint8_t i;
uint8_t hi = userconf.pep_conf[PEP_4][PEP_4_CONF_BRIGHTNESS];
uint8_t lo = userconf.pep_conf[PEP_4][PEP_4_CONF_LOW_BRITE];
if (!pep_work[0]) {
for (i = 0; i < LED_PEP_COUNT; i++) {
led.pep[i] = (pep_work[1] & 1) ? hi : lo;
}
for (i = 0; i < LED_HAT_COUNT; i++) {
led.hat[i] = (pep_work[1] & 1) ? lo : hi;
}
pep_work[0] = userconf.pep_conf[PEP_4][PEP_4_CONF_FLASH_RATE];
} else {
pep_work[0]--;
}
}
/*
* pepper slowly gets eateded
* but it regenerates because it is pepper
*
* work global:
* 0: state index
* 1: eat / regen step
* 2: delay step
*/
static const uint8_t nom_map[5][2] = {
{15, 21},
{13, 23},
{ 6, 24},
{ 5, 27},
{ 2, 29}
};
static void pep_5_nom(uint8_t tick)
{
uint8_t i;
i = nom_map[0][0];
i = (uint8_t)i;
uint8_t start, end;
switch (pep_work[0]) {
case 0:
case 2: { // wait a while
if (!pep_work[2]) {
// just got here; set a new random timeout
i = prng_get8() >> 2;
pep_work[2] = (0xff - 64) + i;
} else {
// wait around for a little while
pep_work[2]--;
if (!pep_work[2]) {
// done here
pep_work[1] = 0;
pep_work[0]++;
}
}
break;
}
case 1: { // eat the pepper
// eat at about one bite per second
if ((tick & 0x7f) != 0) break;
start = 0;
if (!pep_work[1]) {
end = LED_PEP_NOTOP;
} else if (pep_work[1] < 6) {
start = nom_map[pep_work[i] - 1][0];
end = nom_map[pep_work[i] - 1][1];
} else {
end = 0;
}
// set pepper body LEDs to initial on state (or off if pepper is fully eated)
for (i = 0; i < LED_PEP_NOTOP; i++) {
led.pep[i] = end ? 255 : 0;
}
// in this mode we need to light up the top pepper line
for (i = LED_PEP_NOTOP; i < LED_PEP_COUNT; i++) {
led.pep[i] = 200;
}
// clear eated pepper portions, gonna cry
if (end) {
for (i = start; i < end; i++) {
led.pep[i] = 0;
}
}
led_matrix_is_updated();
pep_work[1]++;
if (pep_work[1] > 6) pep_work[0]++;
break;
}
case 3: { // regen the pepper
if (led.pep[pep_work[1]] >= 0xfe) {
// next segment
pep_work[1]++;
if (pep_work[i] >= (LED_PEP_NOTOP - pep_work[i])) {
// we're done regenerating
pep_work[0] = 0;
}
} else {
led.pep[pep_work[1]] += 2;
if (pep_work[1]) {
led.pep[LED_PEP_NOTOP - pep_work[1]] = led.pep[pep_work[1]];
}
led_matrix_is_updated();
}
break;
}
}
}
/*
* make a sharp point at whatever direction is the ground
* note: probably won't be done before con
*/
static void pep_6_accelerometer(uint8_t tick)
{
// not done in time for con
}
/*
* adjust pepper level based on ambient temperature
* ~70F or below: minimum
* ~94F or above: spicy
*/
static void pep_7_heat(uint8_t tick)
{
// not done in time for con
}
/*
const void (*ledprog_pep[8])(uint8_t) = {
(const void (*)(uint8_t))pep_0_flash,
(const void (*)(uint8_t))pep_1_sizzle,
(const void (*)(uint8_t))pep_2_loops,
(const void (*)(uint8_t))pep_3_neon_sign,
(const void (*)(uint8_t))pep_4_alternate,
(const void (*)(uint8_t))pep_5_nom,
(const void (*)(uint8_t))pep_6_accelerometer,
(const void (*)(uint8_t))pep_7_heat
};
*/
void (*ledprog_pep[8])(uint8_t) = {
pep_0_flash,
pep_1_sizzle,
pep_2_loops,
pep_3_neon_sign,
pep_4_alternate,
pep_5_nom,
pep_6_accelerometer,
pep_7_heat
};
void ledprog_pep_init()
{
uint8_t i;
pep_rnd = prng_get16();
// reset LEDs
for (i = 0; i < LED_PEP_COUNT; i++) {
led.pep[i] = 0;
}
for (i = 0; i < LED_HAT_COUNT; i++) {
led.hat[i] = 0;
}
// global program initialization
for (i = 0; i < 4; i++) {
pep_work[i] = 0;
}
// per-program initialization
// there is none on this badge
}