424 lines
7.4 KiB
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]);
|
|
}
|
|
} |