+/* output power levels */
+#define N_POWER_LEVELS 5
+static unsigned char power_levels[N_POWER_LEVELS] = {
+
+};
+
+static unsigned char power_level = 0; // selected power level
+
+/* which state (output on or output off) are we measuring now */
+static volatile unsigned char adc_type, adc_drop;
+#define ADC_RUNAVG_SHIFT 5 // running average shift on batt_on, batt_off
+static volatile uint16_t batt_on, batt_off; // measured voltage
+
+/*
+ * The voltage divider has 1M5 and 300K resistors (i.e. it measures 1/6th of
+ * the real voltage), ADC uses 1.1V internal reference.
+ * Macro to calculate upper eight bits of the ADC running-averaged value
+ * from the voltage in milivolts.
+ */
+#define ADC_1100MV_VALUE 1071 // measured, not exactly 1100
+#define MV_TO_ADC8(mV) ((unsigned char)(((uint32_t)(1UL << ADC_RUNAVG_SHIFT) \
+ * (1024UL * (mV)) \
+ / (6UL * ADC_1100MV_VALUE)) >> 8))
+#define BATT_N_LEVELS 3
+static unsigned char batt_levels[BATT_N_LEVELS] = {
+ MV_TO_ADC8(3500),
+ MV_TO_ADC8(3700),
+ MV_TO_ADC8(3900),
+};
+
+/* timing by WDT */
+static volatile unsigned char jiffies, next_clock_tick;
+
+/* button press duration (in jiffies) */
+#define BUTTON_SHORT_MIN 1
+#define BUTTON_LONG_MIN 10
+
+/* ========= Analog to Digital Converter (battery voltage) ========== */
+static void adc_init()
+{
+ power_adc_enable();
+
+ ADCSRA = _BV(ADEN) // enable
+ | _BV(ADPS1) | _BV(ADPS0) // clk/8 = 125 kHz
+ | _BV(ADIE); // enable IRQ
+ ADMUX = _BV(REFS1) | _BV(MUX1) | _BV(MUX0);
+ // 1.1V reference, PB3 pin, single-ended
+ DIDR0 |= _BV(ADC3D); // PB3 pin as analog input
+}
+
+static void adc_susp()
+{
+ ADCSRA &= ~_BV(ADEN); // disable ADC
+ DIDR0 &= ~_BV(ADC3D); // disable analog input on PB3
+
+ power_adc_disable();
+}
+
+static void adc_start_measurement()
+{
+ ADCSRA |= _BV(ADSC);
+}
+
+ISR(ADC_vect)
+{
+ uint16_t adcw = ADCW;
+
+ if (adc_drop) {
+ adc_drop--;
+ ADCSRA |= _BV(ADSC);
+ return;
+ }
+
+ // TODO: We may want to disable ADC after here to save power,
+ // but compared to the heater power it would be negligible,
+ // so don't bother with it.
+ if (adc_type == 0) {
+ if (batt_off) {
+ batt_off += adcw - (batt_off >> ADC_RUNAVG_SHIFT);
+ } else {
+ batt_off = adcw << ADC_RUNAVG_SHIFT;
+ }
+ } else {
+ if (batt_on) {
+ batt_on += adcw - (batt_on >> ADC_RUNAVG_SHIFT);
+ } else {
+ batt_on = adcw << ADC_RUNAVG_SHIFT;
+ }
+ }
+}
+
+/* ===================== Timer/Counter1 for PWM ===================== */
+static void pwm_init()