/* * 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]); } }