* Status LED:
* When powering up by a button press, the LED goes on to provide a visual
* feedback, and is switched off after the button is released.
- * TODO: After a button press, the # of blinks of the LED reflects the
+ * After a button press, the # of blinks of the LED reflects the
* chosen output power level for some time. Afterwards, it displays
* the battery level.
- * TODO: When the battery is completely exhausted, the output power is switched
+ * When the battery is completely exhausted, the output power is switched
* off, the LED keeps blinking for some time, and then the whole system is
* switched off to avoid deep discharge of the battery.
*
#define N_POWER_LEVELS (sizeof(power_levels) / sizeof(power_levels[0]))
static unsigned char power_level = 0; // selected power level
+static unsigned char power_level_changed; // for visual feedback
+
+#define LED_PWRCHANGE_COUNT 3
+#define LED_BATTEMPTY_COUNT 60
/* timing by WDT */
static volatile unsigned char jiffies, next_clock_tick;
#define BUTTON_SHORT_MIN 1
#define BUTTON_LONG_MIN 10
+
/* ========= Analog to Digital Converter (battery voltage) ========== */
static void adc_init()
{
hw_setup();
}
+/* ============ Status LED blinking =================================== */
+static unsigned char blink_on_time, blink_off_time, n_blinks;
+static unsigned char blink_counter;
+
+static unsigned char battery_level()
+{
+ unsigned char i, adc8;
+
+ // NOTE: we use 8-bit value only, so we don't need lock to protect
+ // us against concurrently running ADC IRQ handler:
+ adc8 = batt_off >> 8;
+
+ for (i = 0; i < BATT_N_LEVELS; i++)
+ if (batt_levels[i] > adc8)
+ break;
+
+ return i;
+}
+
+static void status_led_next_pattern()
+{
+ static unsigned char battery_exhausted;
+
+ if (power_level_changed) {
+ power_level_changed--;
+ n_blinks = power_level + 1;
+ } else {
+ unsigned char b_level = battery_level();
+ if (b_level) {
+ battery_exhausted = 0;
+ } else if (battery_exhausted) {
+ if (!--battery_exhausted)
+ power_down();
+ } else {
+ battery_exhausted = LED_BATTEMPTY_COUNT;
+ }
+
+ n_blinks = b_level + 1;
+ }
+
+ blink_on_time = 2;
+ blink_off_time = 1;
+ blink_counter = 10;
+}
+
+static void timer_blink()
+{
+ if (blink_counter) {
+ blink_counter--;
+ } else if (!status_led_is_on()) {
+ status_led_on();
+ blink_counter = blink_on_time;
+ } else if (n_blinks) {
+ --n_blinks;
+ status_led_off();
+ blink_counter = blink_off_time;
+ } else {
+ status_led_next_pattern();
+ }
+}
+
/* ======== Button press detection and handling ===================== */
static void button_pressed(unsigned char button, unsigned char long_press)
{
// ignore simlultaneous button 1 and 2 press
+ // Note: we set power_level_changed after each button press,
+ // even when the power is at maximum, to provide visual feedback
+ // with status LED.
if (long_press) {
if (button == 1) {
power_down();
+ return;
} else if (button == 2) {
power_level = N_POWER_LEVELS-1;
}
--power_level;
} else {
power_down();
+ return;
}
} else if (button == 2) {
if (power_level < N_POWER_LEVELS-1) {
}
}
}
+ power_level_changed = LED_PWRCHANGE_COUNT;
+ status_led_next_pattern();
}
static unsigned char button_state, button_state_time;
button_state_time = 0;
}
-/* ============ Status LED blinking =================================== */
-static unsigned char blink_on_time, blink_off_time, n_blinks;
-static unsigned char blink_counter;
-
-static unsigned char battery_level()
-{
- unsigned char i, adc8;
-
- // NOTE: we use 8-bit value only, so we don't need lock to protect
- // us against concurrently running ADC IRQ handler:
- adc8 = batt_off >> 8;
-
- for (i = 0; i < BATT_N_LEVELS; i++)
- if (batt_levels[i] > adc8)
- break;
-
- return i;
-}
-
-static void status_led_next_pattern()
-{
-
- // for now, display the selected intensity
- // n_blinks = power_level + 1;
- n_blinks = battery_level() + 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();
- }
-}
-
+/* ===================== Output power control ======================== */
static void calculate_power_level()
{
uint32_t pwm;