+ do {
+ if (++wake_count > WAKEUP_LIMIT)
+ status_led_on(); // inform the user
+
+ _delay_ms(WAKEUP_POLL);
+ } while (buttons_pressed());
+
+ status_led_off();
+
+ return wake_count > WAKEUP_LIMIT;
+}
+
+ISR(PCINT0_vect)
+{
+ // empty - let it wake us from sleep, but do nothing else
+}
+
+/* ==== Watchdog Timer for timing blinks and other periodic tasks ==== */
+static void wdt_init()
+{
+ next_clock_tick = 0;
+ jiffies = 0;
+ WDTCR = _BV(WDIE) | _BV(WDP1); // interrupt mode, 64 ms
+}
+
+static void wdt_susp()
+{
+ wdt_disable();
+}
+
+ISR(WDT_vect) {
+ next_clock_tick = 1;
+ jiffies++;
+}
+
+/* ====== Hardware init, teardown, powering down and waking up ====== */
+static void hw_setup()
+{
+ power_all_disable();
+
+ pwm_init();
+ adc_init();
+ status_led_init();
+ wdt_init();
+}
+
+static void hw_suspend()
+{
+ adc_susp();
+ pwm_susp();
+ status_led_init(); // we don't have a separate _susp() here
+ buttons_susp();
+ wdt_susp();
+
+ power_all_disable();
+}
+
+static void power_down()
+{
+ hw_suspend();
+
+ do {
+ // G'night
+ set_sleep_mode(SLEEP_MODE_PWR_DOWN);
+ sleep_enable();
+ sleep_bod_disable();
+ sei();
+ sleep_cpu();
+
+ // G'morning
+ cli();
+ sleep_disable();
+
+ // allow wakeup by long button-press only
+ } while (!buttons_wait_for_release());
+
+ // OK, wake up now
+ hw_setup();
+}
+
+/* ======== Button press detection and handling ===================== */
+static void button_one_pressed()
+{
+ if (intensity > 0) {
+ pwm_set(steps[--intensity]);
+ } else {
+ power_down();
+ }
+}
+
+static void button_two_pressed()
+{
+ if (intensity < N_STEPS-1) {
+ pwm_set(steps[++intensity]);
+ }
+}
+
+static unsigned char button_state, button_state_time;
+
+static void timer_check_buttons()
+{
+ unsigned char newstate = buttons_pressed();
+
+ if (newstate == button_state) {
+ if (newstate && button_state_time < 4)
+ ++button_state_time;
+ return;
+ }
+
+ if (newstate) {
+ button_state = newstate;
+ button_state_time = 0;
+ return;
+ }
+
+ // just released
+ switch (button_state) {
+ case 1: button_one_pressed();
+ break;
+ case 2: button_two_pressed();
+ break;
+ default: // ignore when both are preseed
+ break;
+ }
+
+ button_state = newstate;
+}
+
+/* ============ Status LED blinking =================================== */
+static unsigned char blink_on_time, blink_off_time, n_blinks;
+static unsigned char blink_counter;
+
+static void status_led_next_pattern()
+{
+ // for now, display the selected intensity
+ n_blinks = intensity + 1;
+ blink_on_time = 0;
+ blink_off_time = 2;
+ blink_counter = 10;
+}
+
+static void timer_blink()
+{
+ if (blink_counter) {
+ blink_counter--;
+ } else if (status_led_is_on()) {
+ status_led_off();
+ blink_counter = blink_off_time;
+ } else if (n_blinks) {
+ --n_blinks;
+ status_led_on();
+ blink_counter = blink_on_time;
+ } else {
+ status_led_next_pattern();
+ }
+}
+
+int main()
+{
+ log_init();
+
+ power_down();
+
+ sei();
+
+ // we try to be completely IRQ-driven, so just wait for IRQs here