From 60f1349e85769a3fe43843b46b4232168c08ca98 Mon Sep 17 00:00:00 2001 From: "Jan \"Yenya\" Kasprzak" Date: Fri, 19 Jul 2013 21:45:27 +0200 Subject: [PATCH] ambient.c: "entering shadow" detection We try to detect the rapid decrease in the ambient light level, such as when entering the dark area (tunnel, deep shadow, etc.). When this happens, we keep the previous (high) ambient zone, and use the night pattern (front light continuously on) for at least 3 seconds, to give the rider's eyes the opportunity to adapt. --- firmware/ambient.c | 47 +++++++++++++++++++++++++++++++++++++--------- firmware/control.c | 6 ++++++ firmware/lights.h | 2 +- 3 files changed, 45 insertions(+), 10 deletions(-) diff --git a/firmware/ambient.c b/firmware/ambient.c index 7a5b8e2..7352f6d 100644 --- a/firmware/ambient.c +++ b/firmware/ambient.c @@ -7,7 +7,7 @@ #define AMBIENT_SLOW_SHIFT 6 // 1 << AMBIENT_SLOW_SHIFT times slower static uint16_t ambient_fast, ambient_slow; -volatile unsigned char ambient_zone; +volatile unsigned char ambient_zone, ambient_shadow; static unsigned char ambient_min, ambient_max, ambient_drop; /* logging */ @@ -32,6 +32,8 @@ static ambient_zone_t ambient_zones[N_AMBIENT_ZONES] = { { 0x02f8, 0xffff }, // day }; +#define SHADOW_DROP_LIMIT 0x20 // in ADC units (0..0x3ff) + void init_ambient() { ambient_slow = 0; @@ -40,6 +42,7 @@ void init_ambient() ambient_min = 0xFF; ambient_zone = 1; ambient_drop = 0; + ambient_shadow = 0; ambient_log_offset = eeprom_read_byte(&ambient_log_offset_stored); @@ -103,34 +106,60 @@ static unsigned char val_to_zone(uint16_t ambient_val) void ambient_adc(uint16_t adcval) { - unsigned char new_zone, user_zone; + unsigned char new_zone, user_zone, new_shadow = 0; unsigned char byte_fast, byte_slow, drop; - uint16_t a_10bit; + uint16_t fast_10bit, slow_10bit; // running avg - shorter timespan ambient_fast += adcval - (ambient_fast >> AMBIENT_FAST_SHIFT); // running avg - longer timespan - a_10bit = ambient_fast >> (AMBIENT_FAST_SHIFT + AMBIENT_ADC_SHIFT); - ambient_slow += a_10bit - (ambient_slow >> AMBIENT_SLOW_SHIFT); + fast_10bit = ambient_fast >> (AMBIENT_FAST_SHIFT + AMBIENT_ADC_SHIFT); + ambient_slow += fast_10bit - (ambient_slow >> AMBIENT_SLOW_SHIFT); // ambient zones are governed by shorter timespan by default - new_zone = val_to_zone(a_10bit); + new_zone = val_to_zone(fast_10bit); + + slow_10bit = ambient_slow >> AMBIENT_SLOW_SHIFT; if (new_zone > 1 && ( new_zone == ambient_zone-1 || new_zone == ambient_zone+1)) { // but change to the neighbouring zone is governed by _slow, // except to the darkest zone, where we want fast reaction. - new_zone = val_to_zone(ambient_slow >> AMBIENT_SLOW_SHIFT); + new_zone = val_to_zone(slow_10bit); } // user_param ambient zone override if ((user_zone = get_user_param(0)) > 0) new_zone = user_zone - 1; + // are we entering the shadow? + if (!user_zone && new_zone < ambient_zone + && ambient_zone >= 2 && slow_10bit > fast_10bit + && slow_10bit - fast_10bit >= SHADOW_DROP_LIMIT) { + // we are entering the shadow + new_shadow = 0x30; + } + + if (ambient_shadow) { + if (new_shadow) { + new_zone = ambient_zone; // don't change while entering shadow + ambient_shadow = new_shadow; // update the timeout + } else { + ambient_shadow--; + if (!ambient_shadow) { // leaving the shadow + ambient_zone_changed(); + } + } + } else if (new_shadow) { + ambient_shadow = new_shadow; // set up the timeout + new_zone = ambient_zone; // don't change while entering shadow + ambient_zone_changed(); // notify others the first time + } + // TODO: maybe use these values instead of 10-bit? - byte_fast = a_10bit >> 2; - byte_slow = ambient_slow >> (AMBIENT_SLOW_SHIFT + 2); + byte_fast = fast_10bit >> 2; + byte_slow = slow_10bit >> 2; if (byte_slow > byte_fast) { drop = byte_slow - byte_fast; diff --git a/firmware/control.c b/firmware/control.c index a0d2451..2b1a736 100644 --- a/firmware/control.c +++ b/firmware/control.c @@ -140,6 +140,9 @@ pattern_t *pwmled_pattern_select() if (err_flags.err_battery) return slow_pattern; + if (ambient_shadow) + return night_pattern; + switch (ambient_zone) { case 0: return night_pattern; case 1: @@ -185,6 +188,9 @@ pattern_t *illumination_led_pattern_select() if (err_flags.err_battery) return NULL; + if (ambient_shadow) + return on_pattern; + switch (ambient_zone) { case 0: return dim_mode ? number_pattern(1, 1) diff --git a/firmware/lights.h b/firmware/lights.h index 3af09cd..72d7d33 100644 --- a/firmware/lights.h +++ b/firmware/lights.h @@ -81,7 +81,7 @@ void gpio_set(unsigned char n, unsigned char on); void init_ambient(); void susp_ambient(); void ambient_log_min_max(); -extern volatile unsigned char ambient_zone; +extern volatile unsigned char ambient_zone, ambient_shadow; void ambient_adc(uint16_t adc_val); /* pattern.c */ -- 2.39.3