sc7-testo-firmware/src/rgbprog.c

424 lines
7.4 KiB
C

/*
* rgbprog.c: making your eyes light up
*
* program notes:
* knob[0] is the left knob, 0-255.
* there are 8 programs selected by the knob[0] position.
*
* k0 passed to rgb programs is the 5 bits of position
* of the knob[0] value for the selected program.
* these can be used within the program.
*
* knob[1] is the right knob, 0-255.
*
* raw knob values can be read from adc_avg[ADC_SET0] (left)
* and adc_avg[ADC_SET1] (right).
*
* raw values are safe to use from the left knob,
* but will vary on the right knob depending on board version.
* thus it is recommended to only use the 8-bit smoothed
* value for the right knob.
*
* file creation: 20231015 0119
*/
#include "led.h"
#include "hsv2rgb.h"
#include "rand.h"
#include "userio.h"
#define hsv2rgb(idx, h, s, v) hsv2rgb_8b(h, s, v, &rgb[idx].r, &rgb[idx].g, &rgb[idx].b)
void rgbprog_rainbow(uint8_t k0);
void rgbprog_rainbow_offset(uint8_t k0);
void rgbprog_static(uint8_t k0);
void rgbprog_flicker(uint8_t k0);
void rgbprog_randcolorfadebetween(uint8_t k0);
void rgbprog_randcolor(uint8_t k0);
void rgbprog_randcolorfadeinout(uint8_t k0);
void rgbprog_prog7(uint8_t k0);
void rgbprog_set1_error();
static void (*proglist[8])(uint8_t) = {
rgbprog_rainbow,
rgbprog_rainbow_offset,
rgbprog_static,
rgbprog_flicker,
rgbprog_randcolorfadebetween,
rgbprog_randcolor,
rgbprog_randcolorfadeinout,
rgbprog_prog7
};
static uint16_t brite = 0;
static color_hsv hsv[2];
static color_rgb rgb[2];
static color_rgb rfade;
void rgb_setled(uint8_t ledidx, color_rgb *rgb)
{
led_setrgb(ledidx, rgb->r << brite, rgb->g << brite, rgb->b << brite);
}
void rgb_fromhsv(uint8_t ledidx, uint16_t h, uint8_t s, uint8_t v)
{
hsv2rgb_8b(h, s, v, &rgb[ledidx].r, &rgb[ledidx].g, &rgb[ledidx].b);
}
void rgb_fade(uint8_t fade)
{
uint8_t i;
uint16_t mod, invmod;
uint8_t *rf = (uint8_t *)&rfade;
uint8_t *r[2] = { (uint8_t *)&rgb[0], (uint8_t *)&rgb[1] };
mod = fade + 1;
invmod = (255 - fade) + 1;
for (i = 0; i < 3; i++) {
if (!fade) {
rf[i] = r[0][i];
continue;
}
if (fade == 0xff) {
rf[i] = r[1][i];
continue;
}
rf[i] = ((r[0][i] * invmod) >> 8) + ((r[1][i] * mod) >> 8);
}
}
void rgbprog_run()
{
uint32_t i;
uint8_t j;
// if the button has been pushed, change the brightness
if (userio_get_btn() > 0) {
brite++;
brite &= 0x3;
}
// if SET1 is out of range, indicate that instead of
// running the normal program
if (userio_get_set1_limit()) {
rgbprog_set1_error();
return;
}
// which program to run?
j = 0;
for (i = 32; i <= 256; i += 32) {
if (knob[0] < i) {
if (proglist[j]) {
proglist[j](knob[0] & 0x1f);
}
break;
}
j++;
}
}
/*
* program 0: rainbow program
*
* both eyes are set to same rgb rainbow pattern
*/
void rgbprog_rainbow(uint8_t k0)
{
int16_t w;
w = knob[1];
w *= 2;
w = 256 - w;
hsv[0].h += w;
if (hsv[0].h < 0) hsv[0].h += 0x3000;
hsv[0].h %= 0x3000;
hsv2rgb(0, hsv[0].h >> 3, 255, 255);
rgb_setled(0, &rgb[0]);
rgb_setled(1, &rgb[0]);
}
/*
* program 1: rainbow program
*
* both eyes are set to rgb rainbow pattern,
* with offset between the eyes
*/
void rgbprog_rainbow_offset(uint8_t k0)
{
rgbprog_rainbow(k0);
hsv[1].h = hsv[0].h;
hsv[1].h += k0 << 6;
hsv[1].h %= 0x3000;
hsv2rgb(1, hsv[1].h >> 3, 255, 255);
rgb_setled(1, &rgb[1]);
}
/*
* program 2: static color
*
* both eyes are set to a static color
*
* left knob adjusts saturation
* right knob adjusts color hue
*/
void rgbprog_static(uint8_t k0)
{
hsv[0].h = knob[1] * 6;
hsv2rgb(0, hsv[0].h, 131 + (k0 << 2), 255);
rgb_setled(0, &rgb[0]);
rgb_setled(1, &rgb[0]);
}
/*
* program 3: flicker
*
* both eyes are set to a static flickering color
* left knob adjusts flicker level
* right knob adjusts color hue
*/
void rgbprog_flicker(uint8_t k0)
{
uint8_t i;
uint8_t val;
// operate only 1/4 of the time
hsv[0].s++;
hsv[0].s &= 3;
if (hsv[0].s) return;
hsv[0].h = knob[1] * 6;
// independent flicker for each eye
for (i = 0; i < 2; i++) {
// left knob sets flicker
if ((rand() & 0xff) > (k0 << 3)) {
// full bright
val = 0xff;
} else {
// flicker
val = 0x2f;
}
hsv2rgb(i, hsv[0].h, 255, val);
rgb_setled(i, &rgb[i]);
}
}
/*
* program 4: random fade between colors
*
* linear fade between two random colors
*/
void rgbprog_randcolorfadebetween(uint8_t k0)
{
int16_t w;
// set delay based on left knob
hsv[0].s++;
if (hsv[0].s > (k0 >> 1)) hsv[0].s = 0;
if (hsv[0].s) return;
// update new colors at the end of every fade
hsv[0].v += 3;
if (hsv[0].v <= 2) {
// set new initial colors
hsv[0].h = hsv[1].h;
hsv[1].h = rand() % 1536;
// clamp discrete colors to 64
w = 4 * 6;
hsv[1].h /= w;
hsv[1].h *= w;
hsv2rgb(0, hsv[0].h, 255, 255);
hsv2rgb(1, hsv[1].h, 255, 255);
}
// do the fade
rgb_fade(hsv[0].v);
// and output the result
rgb_setled(0, &rfade);
rgb_setled(1, &rfade);
}
/*
* program 5:
*
* change between two random colors
*
* left knob sets single color or dual color
* right knob sets speed
*/
void rgbprog_randcolor(uint8_t k0)
{
// set delay based on right knob
hsv[1].h += knob[1];
hsv[1].h++;
if (hsv[1].h >= 0x1000) { // 1/16 rate
hsv[1].h -= 0x1000;
// update time
hsv[0].h = rand() % 1536;
hsv2rgb(0, hsv[0].h, 255, 255);
if (k0 >= 16) {
rgb_setled(rand() & 1, &rgb[0]);
} else {
rgb_setled(0, &rgb[0]);
rgb_setled(1, &rgb[0]);
}
}
}
/*
* program 6:
*
* fade up into a random color, hold, then fade out
*
* left knob sets dwell
* right knob sets cycle time
*/
void rgbprog_randcolorfadeinout(uint8_t k0)
{
uint16_t w;
// operate only 1/4 of the time
hsv[0].s++;
hsv[0].s &= 3;
if (hsv[0].s) return;
// hsv[1].h contains fade counter
// hsv[1].s contains dwell counter
// hsv[1].v contains our state
hsv[1].v &= 0x3;
switch (hsv[1].v) {
case 0:
case 2: {
// ramp up/down
// first run or new run?
if (!hsv[1].h) {
// set a new hue
hsv[0].h = rand() % 1536;
}
// fade up or down
hsv[1].h += (knob[1]);
hsv[1].h++;
// clamp value
if (hsv[1].h > 0x7ff) {
hsv[1].h = 0x7ff;
}
// set output
w = hsv[1].v ? (0x7ff - hsv[1].h) : hsv[1].h;
w >>= 3;
hsv2rgb(0, hsv[0].h, 255, (w & 0xff));
// are we done?
if (hsv[1].h == 0x7ff) {
hsv[1].h = 0;
hsv[1].v++;
}
break;
}
case 1:
case 3: {
// hold
// just getting to this step?
if (!hsv[1].h) {
// initialize step
hsv[1].h++;
hsv[1].s = 0;
} else {
// delay here
w = hsv[1].s;
w += k0;
w++;
// are we done?
if (w > 0x100) {
if (hsv[1].v == 3) {
hsv[1].h = 0;
}
hsv[1].v++;
} else {
hsv[1].s = w & 0xff;
}
}
}
}
rgb_setled(0, &rgb[0]);
rgb_setled(1, &rgb[0]);
}
/*
* program 7:
*
* turns LEDs off.
*
* it's basically an empty program.
* if you want to write your own, do it here
*
* maybe you could write a smart morse generator,
* or a cop mode, or...
*/
void rgbprog_prog7(uint8_t k0)
{
rgb[0].r = rgb[0].g = rgb[0].b = 0;
rgb_setled(0, &rgb[0]);
rgb_setled(1, &rgb[0]);
}
/*
* internal program:
*
* flashes LEDs, indicating a SET1 knob error.
*/
void rgbprog_set1_error()
{
hsv[1].s++;
if (!hsv[1].s) {
hsv[1].v++;
hsv[1].v &= 1;
hsv[0].v = hsv[1].v ^ 1;
rgb[0].r = 255;
rgb[0].g = 0;
rgb[0].b = 0;
rgb_setled(hsv[1].v, &rgb[0]);
rgb[0].r = 0;
rgb_setled(hsv[0].v, &rgb[0]);
}
}