+led_t red;
+led_t grn;
+led_t blu;
+led_t wht;
+bit on;
+unsigned char speed;
+int fade_steps;
+
+void start_fade()
+{
+ /* RGB PWM values are 8 bits, but computations are done in 15
+ * (leaving room for a sign bit), so leds_set() uses >>7 to convert
+ * to PWM values.
+ */
+ int newr, newg, newb, neww;
+
+ /* New RGB values; all zero is not a valid option */
+ do {
+ newr = rand();
+ newg = rand();
+ newb = rand();
+ neww = rand();
+ } while (newr == 0 && newg == 0 && newb == 0 && neww == 0);
+
+ /* Random # of steps to reach the new color */
+ fade_steps = rand_fade_steps(speed);
+
+ /* Compute increment per fade step, and remainder, for each led */
+ red.increment = (newr - red.value) / fade_steps;
+ red.remainder = newr - (red.value + red.increment * fade_steps);
+ grn.increment = (newg - grn.value) / fade_steps;
+ grn.remainder = newg - (grn.value + grn.increment * fade_steps);
+ blu.increment = (newb - blu.value) / fade_steps;
+ blu.remainder = newb - (blu.value + blu.increment * fade_steps);
+ wht.increment = (neww - wht.value) / fade_steps;
+ wht.remainder = neww - (wht.value + wht.increment * fade_steps);
+
+ /* Start the fade timer */
+ tmr_startPeriodic(TMR_FADE, 1); /* 32.768 msec */
+}
+
+void turnOn()
+{
+ dbgpin_high();
+ on = 1;
+ red.value = 0;
+ grn.value = 0;
+ blu.value = 0;
+ wht.value = 0;
+ leds_set(red, grn, blu, wht);
+ rgb_on();
+ start_fade();
+}
+
+void turnOff()
+{
+ /* Event on to off, either by switch or auto-off timer */
+ tmr_stop(TMR_INCOLOR);
+ tmr_stop(TMR_FADE);
+ rgb_off();
+ dbgpin_low();
+ on = 0;
+}
+
+void pb_task()
+{
+ if (btn_pb() == BTN_PB_UP) {
+ speed = (speed + 1) & ~4;
+ tmr_stop(TMR_INCOLOR);
+ start_fade();
+ }
+ btn_pben();
+}
+
+void rs_task()
+{
+ switch (btn_rs()) {
+ case BTN_RS_OFF:
+ tmr_stop(TMR_AUTO_OFFON);
+ turnOff();
+ break;
+ case BTN_RS_RIGHT:
+ tmr_start(TMR_AUTO_OFFON, AUTO_OFF_COUNT);
+ /* fall through */
+ case BTN_RS_LEFT:
+ turnOn();
+ break;
+ }
+ btn_rsen();
+}
+
+void fade_task()
+{
+ red.value += red.increment;
+ grn.value += grn.increment;
+ blu.value += blu.increment;
+ wht.value += wht.increment;
+ if (--fade_steps == 0) {
+ /* This is the last fade step. Finalize the RGB led states and decide how
+ * long to stay in this color.
+ */
+ red.value += red.remainder;
+ grn.value += grn.remainder;
+ blu.value += blu.remainder;
+ wht.value += wht.remainder;
+ tmr_stop(TMR_FADE);
+ tmr_start(TMR_INCOLOR, rand_incolor_steps(speed));
+ }
+ leds_set(red, grn, blu, wht);
+}
+
+void auto_offon_task()
+{
+ if (on) {
+ turnOff();
+ if (btn_rs() == BTN_RS_RIGHT)
+ tmr_start(TMR_AUTO_OFFON, AUTO_ON_COUNT);
+ } else /* off */ {
+ turnOn();
+ if (btn_rs() == BTN_RS_RIGHT)
+ tmr_start(TMR_AUTO_OFFON, AUTO_OFF_COUNT);
+ }
+}
+
+void user_boot()