2 #include <avr/eeprom.h>
6 #define AMBIENT_FAST_SHIFT 2 // running avg of ADC vals
7 #define AMBIENT_SLOW_SHIFT 6 // 1 << AMBIENT_SLOW_SHIFT times slower
9 static uint16_t ambient_fast, ambient_slow;
10 volatile unsigned char ambient_zone;
11 static unsigned char ambient_min, ambient_max, ambient_drop;
14 #define AMBIENT_LOG_SIZE 128
15 static unsigned char ambient_log_offset_stored EEMEM;
16 static unsigned char ambient_log_offset;
17 static unsigned char ambient_log[AMBIENT_LOG_SIZE] EEMEM;
19 /* My photodiode reads 0x00C5 .. 0x033B */
21 uint16_t lo, hi; // TODO: consider changing this to bytes
25 * Note: these have to be sorted, starting with 0, ending with 0xFFFF
26 * and having small overlaps in order to provide a bit of hysteresis.
28 static ambient_zone_t ambient_zones[N_AMBIENT_ZONES] = {
29 { 0x0000, 0x0250 }, // dark
30 { 0x0240, 0x02e0 }, // evening
31 { 0x02c0, 0x0300 }, // dawn
32 { 0x02f8, 0xffff }, // day
44 ambient_log_offset = eeprom_read_byte(&ambient_log_offset_stored);
46 if (ambient_log_offset == AMBIENT_LOG_SIZE)
47 ambient_log_offset = 0; // start over
52 unsigned char stored_offset;
54 ambient_log_min_max();
56 stored_offset = eeprom_read_byte(&ambient_log_offset_stored);
57 if (stored_offset != ambient_log_offset)
58 eeprom_write_byte(&ambient_log_offset_stored,
62 void ambient_log_min_max()
64 if (ambient_log_offset >= AMBIENT_LOG_SIZE - 1)
67 ambient_max -= ambient_min;
73 if (ambient_drop > 15)
76 eeprom_write_byte(&ambient_log[ambient_log_offset++], ambient_min);
77 eeprom_write_byte(&ambient_log[ambient_log_offset++],
78 (ambient_max << 4) | ambient_drop);
85 static inline void ambient_zone_changed()
87 pwmled_select_brightness();
91 static unsigned char val_to_zone(uint16_t ambient_val)
93 unsigned char new_zone = ambient_zone;
95 while (ambient_zones[new_zone].lo > ambient_val)
98 while (ambient_zones[new_zone].hi < ambient_val)
104 void ambient_adc(uint16_t adcval)
106 unsigned char new_zone, user_zone;
107 unsigned char byte_fast, byte_slow, drop;
110 // running avg - shorter timespan
111 ambient_fast += adcval - (ambient_fast >> AMBIENT_FAST_SHIFT);
113 // running avg - longer timespan
114 a_10bit = ambient_fast >> (AMBIENT_FAST_SHIFT + AMBIENT_ADC_SHIFT);
115 ambient_slow += a_10bit - (ambient_slow >> AMBIENT_SLOW_SHIFT);
117 // ambient zones are governed by shorter timespan by default
118 new_zone = val_to_zone(a_10bit);
120 if (new_zone > 1 && (
121 new_zone == ambient_zone-1 || new_zone == ambient_zone+1)) {
122 // but change to the neighbouring zone is governed by _slow,
123 // except to the darkest zone, where we want fast reaction.
124 new_zone = val_to_zone(ambient_slow >> AMBIENT_SLOW_SHIFT);
127 // user_param ambient zone override
128 if ((user_zone = get_user_param(0)) > 0)
129 new_zone = user_zone - 1;
131 // TODO: maybe use these values instead of 10-bit?
132 byte_fast = a_10bit >> 2;
133 byte_slow = ambient_slow >> (AMBIENT_SLOW_SHIFT + 2);
135 if (byte_slow > byte_fast) {
136 drop = byte_slow - byte_fast;
137 if (drop > ambient_drop)
141 if (ambient_min > byte_slow)
142 ambient_min = byte_slow;
144 if (ambient_max < byte_slow)
145 ambient_max = byte_slow;
147 if (new_zone != ambient_zone) {
148 ambient_zone = new_zone;
151 log_byte(ambient_zone);
155 ambient_zone_changed();