X-Git-Url: https://www.fi.muni.cz/~kas/git//home/kas/public_html/git/?p=bike-lights.git;a=blobdiff_plain;f=firmware%2Fambient.c;h=ab28a20faf1ce95719cdd8ff4386ef9b90790af2;hp=02377ccd46586ab1895083adeb09dbda77ff50e5;hb=HEAD;hpb=4f140698e7be15ec5a32e3bdb3f8ff9ea1c46758 diff --git a/firmware/ambient.c b/firmware/ambient.c index 02377cc..3ae15d3 100644 --- a/firmware/ambient.c +++ b/firmware/ambient.c @@ -3,40 +3,53 @@ #include "lights.h" -#define AMBIENT_VAL_SHIFT 2 -static uint16_t ambient_val; -volatile unsigned char ambient_zone; -static unsigned char ambient_min, ambient_max; +#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, ambient_shadow; +static unsigned char ambient_min, ambient_max, ambient_drop; /* logging */ -#define AMBIENT_LOG_SIZE 128 +#define AMBIENT_LOG_SIZE 256 static unsigned char ambient_log_offset_stored EEMEM; static unsigned char ambient_log_offset; 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; /* * Note: these have to be sorted, starting with 0, ending with 0xFFFF * and having small overlaps in order to provide a bit of hysteresis. */ -static ambient_zone_t ambient_zones[] = { - { 0x0000 , 0x0280<= AMBIENT_LOG_SIZE - 1) - return; + ambient_log_offset = 0; // start over + + 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); + eeprom_write_byte(&ambient_log[ambient_log_offset++], + (ambient_max << 4) | ambient_drop); ambient_min = 0xFF; ambient_max = 0; + ambient_drop = 0; } -void ambient_zone_changed() +static inline void ambient_zone_changed() { -#if 1 - log_byte(0xab); - log_byte(ambient_zone); - log_word(ambient_val); - log_flush(); -#endif + pwmled_select_brightness(); + pattern_reload(); +} + +static unsigned char val_to_zone(uint16_t ambient_val) +{ + unsigned char new_zone = ambient_zone; + + if (new_zone >= N_AMBIENT_ZONES) + new_zone = N_AMBIENT_ZONES-1; + + while (ambient_zones[new_zone].lo > ambient_val) + new_zone--; + + while (ambient_zones[new_zone].hi < ambient_val) + new_zone++; - // led_set_pattern(N_PWMLEDS, status_led_pattern_select()); - // led_set_pattern(N_PWMLEDS+1, illumination_led_pattern_select()); - // pattern_reload(); + return new_zone; } void ambient_adc(uint16_t adcval) { - unsigned char old_zone = ambient_zone; - unsigned char byte_val; + unsigned char new_zone, user_zone, new_shadow = 0; + unsigned char byte_fast, byte_slow, drop; + uint16_t fast_10bit, slow_10bit; - ambient_val += adcval - (ambient_val - >> (AMBIENT_VAL_SHIFT - AMBIENT_ADC_SHIFT)); + // running avg - shorter timespan + ambient_fast += adcval - (ambient_fast >> AMBIENT_FAST_SHIFT); - while (ambient_zones[ambient_zone].lo > ambient_val) - ambient_zone--; + // running avg - longer timespan + fast_10bit = ambient_fast >> (AMBIENT_FAST_SHIFT + AMBIENT_ADC_SHIFT); + ambient_slow += fast_10bit - (ambient_slow >> AMBIENT_SLOW_SHIFT); - while (ambient_zones[ambient_zone].hi < ambient_val) - ambient_zone++; + // ambient zones are governed by shorter timespan by default + new_zone = val_to_zone(fast_10bit); - byte_val = adcval >> 2; + slow_10bit = ambient_slow >> AMBIENT_SLOW_SHIFT; - if (ambient_min > byte_val) - ambient_min = byte_val; + if ((new_zone > ambient_zone) + || (new_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(slow_10bit); + } + + // user_param ambient zone override + if ((user_zone = get_user_param(0)) > 0) + new_zone = user_zone - 1; + +#if 0 // ignore shadow-entering code altogether for now + // 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 + } +#endif + + // TODO: maybe use these values instead of 10-bit? + byte_fast = fast_10bit >> 2; + byte_slow = slow_10bit >> 2; - if (ambient_max < byte_val) - ambient_max = byte_val; + if (byte_slow > byte_fast) { + drop = byte_slow - byte_fast; + if (drop > ambient_drop) + ambient_drop = drop; + } + + if (ambient_min > byte_slow) + ambient_min = byte_slow; + + if (ambient_max < byte_slow) + ambient_max = byte_slow; + + if (new_zone != ambient_zone) { + ambient_zone = new_zone; #if 0 - if (old_zone != ambient_zone) { log_byte(0xab); log_byte(ambient_zone); log_word(adcval); log_flush(); - } - // ambient_zone_changed(); #endif + ambient_zone_changed(); + } }