]> www.fi.muni.cz Git - bike-lights.git/blobdiff - firmware/ambient.c
ambient.c: "entering shadow" detection
[bike-lights.git] / firmware / ambient.c
index 7a5b8e2c3c621f43a3c6aad52a6d5087ab304c1a..7352f6d5779359c2b1b2471091618e0a07641c78 100644 (file)
@@ -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;