]> www.fi.muni.cz Git - bike-lights.git/blobdiff - firmware/ambient.c
ambient.c: rewrite
[bike-lights.git] / firmware / ambient.c
index aca12577fd1f4876549232b817e48eda534360f4..904f2161f5fba06f4b27f38cf23b6a9c2b90417d 100644 (file)
@@ -3,10 +3,12 @@
 
 #include "lights.h"
 
-#define AMBIENT_VAL_SHIFT 2
-static uint16_t ambient_val, ambient_val16;
+#define AMBIENT_FAST_SHIFT 2   // running avg of ADC vals
+#define AMBIENT_SLOW_SHIFT 6   // 1 << AMBIENT_SLOW_SHIFT times slower
+
+static uint16_t ambient_fast, ambient_slow;
 volatile unsigned char ambient_zone;
-static unsigned char ambient_min, ambient_max, ambient_16drop;
+static unsigned char ambient_min, ambient_max, ambient_drop;
 
 /* logging */
 #define AMBIENT_LOG_SIZE 128
@@ -16,7 +18,7 @@ static unsigned char ambient_log[AMBIENT_LOG_SIZE] EEMEM;
 
 /* My photodiode reads 0x00C5 .. 0x033B */
 typedef struct {
-       uint16_t lo, hi;
+       uint16_t lo, hi; // TODO: consider changing this to bytes
 } ambient_zone_t;
 
 /*
@@ -24,20 +26,20 @@ typedef struct {
  * and having small overlaps in order to provide a bit of hysteresis.
  */
 static ambient_zone_t ambient_zones[N_AMBIENT_ZONES] = {
-       { 0x0000                   , 0x0250<<AMBIENT_VAL_SHIFT }, // dark
-       { 0x0240<<AMBIENT_VAL_SHIFT, 0x02e0<<AMBIENT_VAL_SHIFT }, // evening
-       { 0x02c0<<AMBIENT_VAL_SHIFT, 0x0306<<AMBIENT_VAL_SHIFT }, // dawn
-       { 0x02f8<<AMBIENT_VAL_SHIFT, 0xffff                    }, // day
+       { 0x0000, 0x0250 }, // dark
+       { 0x0240, 0x02e0 }, // evening
+       { 0x02c0, 0x0306 }, // dawn
+       { 0x02f8, 0xffff }, // day
 };
 
 void init_ambient()
 {
-       ambient_val = 0;
-       ambient_val16 = 0;
+       ambient_slow = 0;
+       ambient_fast = 0;
        ambient_max = 0;
        ambient_min = 0xFF;
        ambient_zone = 1;
-       ambient_16drop = 0;
+       ambient_drop = 0;
 
        ambient_log_offset = eeprom_read_byte(&ambient_log_offset_stored);
 
@@ -62,13 +64,22 @@ void ambient_log_min_max()
        if (ambient_log_offset >= AMBIENT_LOG_SIZE - 1)
                return;
 
-       // eeprom_write_byte(&ambient_log[ambient_log_offset++], ambient_min);
-       eeprom_write_byte(&ambient_log[ambient_log_offset++], ambient_max);
-       eeprom_write_byte(&ambient_log[ambient_log_offset++], ambient_16drop);
+       ambient_max -= ambient_min;
+       ambient_max >>= 2;
+       if (ambient_max > 15)
+               ambient_max = 15;
+
+       ambient_drop >>= 2;
+       if (ambient_drop > 15)
+               ambient_drop = 15;
+
+       eeprom_write_byte(&ambient_log[ambient_log_offset++], ambient_min);
+       eeprom_write_byte(&ambient_log[ambient_log_offset++],
+               (ambient_max << 4) | ambient_drop);
 
        ambient_min = 0xFF;
        ambient_max = 0;
-       ambient_16drop = 0;
+       ambient_drop = 0;
 }
 
 static inline void ambient_zone_changed()
@@ -77,42 +88,64 @@ static inline void ambient_zone_changed()
        pattern_reload();
 }
 
-void ambient_adc(uint16_t adcval)
+static unsigned char val_to_zone(uint16_t ambient_val)
 {
-       unsigned char old_zone = ambient_zone;
-       unsigned char byte_val, byte_val16;
+       unsigned char new_zone = ambient_zone;
 
-       ambient_val += adcval - (ambient_val
-               >> (AMBIENT_VAL_SHIFT - AMBIENT_ADC_SHIFT));
+       while (ambient_zones[new_zone].lo > ambient_val)
+               new_zone--;
+
+       while (ambient_zones[new_zone].hi < ambient_val)
+               new_zone++;
+
+       return new_zone;
+}
 
-       while (ambient_zones[ambient_zone].lo > ambient_val)
-               ambient_zone--;
+void ambient_adc(uint16_t adcval)
+{
+       unsigned char new_zone, user_zone;
+       unsigned char byte_fast, byte_slow, drop;
+       uint16_t a_10bit;
 
-       while (ambient_zones[ambient_zone].hi < ambient_val)
-               ambient_zone++;
+       // running avg - shorter timespan
+       ambient_fast += adcval - (ambient_fast >> AMBIENT_FAST_SHIFT);
 
-       byte_val = ambient_val >> (2 + AMBIENT_VAL_SHIFT - AMBIENT_ADC_SHIFT);
+       // running avg - longer timespan
+       a_10bit = ambient_fast >> (AMBIENT_FAST_SHIFT + AMBIENT_ADC_SHIFT);
+       ambient_slow += a_10bit - (ambient_slow >> AMBIENT_SLOW_SHIFT);
 
-       ambient_val16 += byte_val - (ambient_val16 >> 4);
-       byte_val16 = ambient_val16 >> 4;
+       // ambient zones are governed by shorter timespan by default
+       new_zone = val_to_zone(a_10bit);
 
-       if (byte_val16 > byte_val) {
-               byte_val16 -= byte_val;
-               if (byte_val16 > ambient_16drop)
-                       ambient_16drop = byte_val16;
+       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);
        }
 
-       if (ambient_min > byte_val)
-               ambient_min = byte_val;
+       // user_param ambient zone override
+       if ((user_zone = get_user_param(0)) > 0)
+               new_zone = user_zone - 1;
 
-       if (ambient_max < byte_val)
-               ambient_max = byte_val;
+       // TODO: maybe use these values instead of 10-bit?
+       byte_fast = a_10bit >> 2;
+       byte_slow = ambient_slow >> (AMBIENT_SLOW_SHIFT + 2);
 
-       // user_param ambient zone override
-       if ((byte_val = get_user_param(0)) > 0)
-               ambient_zone = byte_val - 1;
+       if (byte_slow > byte_fast) {
+               drop = byte_slow - byte_fast;
+               if (drop > ambient_drop)
+                       ambient_drop = drop;
+       }
+
+       if (ambient_min > byte_fast)
+               ambient_min = byte_fast;
+
+       if (ambient_max < byte_fast)
+               ambient_max = byte_fast;
 
-       if (old_zone != ambient_zone) {
+       if (new_zone != ambient_zone) {
+               ambient_zone = new_zone;
 #if 0
                log_byte(0xab);
                log_byte(ambient_zone);