ambient.c: settings for my wife's bike
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.
Error flags, error reporting - all error flags are in the bit array err_flags, including braking and booting (this is unused yet, the idea is to report successful boot and pwmled init somehow). - error status is reported as num_pattern(err, 1) by the status LED - error status (if any) can be cleared by pressing the button 1 (which takes precedence over the panic mode)
ambient.c: user-settable ambient light zone User-settable parameter 0 is now the ambient light zone: Value 0 means to use the ambient light sensor, values 1 .. N_AMBIENT_ZONES represent the manually set light level.
buttons.c: setup mode rework See the comment near the top of buttons.c for the description of how the setup mode works.
logic for setting brightness We set the brightness in an universal function pwmled_select_brightness(), and this function is called on various events, such as - ambient light zone change - dim mode toggle For now, dim mode means different brightness only for night-ish modes, because for day modes, slow_pattern uses level 1 as main brightness.
braking is handled behind the patterns inside pattern.c See the comment above pwmled_update_mode(): This is tricky: we use a single pattern for all three pwmleds, but on some occasions, we want to be able to modify only a single pwmled status without affecting other outputs. For example, during braking, we want to modify only the rear pwmled status. We don't use a separate "braking" pattern for every other pattern used, but instead we change the pwmled0 status regardless of the original value when braking. The rule is the following: - if during braking the pwmled2 (front) is at mode 2, we switch it to mode 3 (which has the same target current) to avoid flicker. - if pwmled0 (rear) is off, we set it to mode 2 (if it is with mode 1, we keep it at mode 1) TODO: something similar should be done for the "entering the dark area" condition, where we want to switch pwmled2 (front) on, to mode 2.
Common patterns rewrite slowN_pattern, normalN_pattern, and onN_pattern for N=(1..4) rewritten to be brightness-independent, and to avoid switching multiple outputs on at once, if possible. If not (such as when PWMLED 2 is continuously on), use mode 2 and 3 with the same target current to accomodate for different battery voltages when more than one output is running. TODO: actually set brightness based on various conditions, such as ambient lights, user-requested dim mode, etc.
PWMLED: proof-of-concept brightness setting In order to save space for patterns, we set the brightness independently from pattern. Each brightness has only two levels for PWMLED 0 and 2, and one for PWMLED 1. Patterns can then use two-bit values for each PWMLED (one-bit for PWMLED 1), with the following meaning: 0: off 1: level 1 2: level 2 3: also level 2, with a separate state stored. This can be used for saving regulation value for a single current level with and without other outputs running, or with different levels of other output. This is in order to avoid flicker when one PWMLED (usually the front one) is steady on, and the others are blinking.
PWM LEDs driven by a single pattern Pattern sources renumbered: 0 - all three PWM LEDs 1 - status led 2 - illumination LED 4 - laser LED
Disable WDT as early as possible Apparently, after WDT reset, WDT is still running, and has to be disabled. Otherwise it will kick in again during the initialization. We want to indicate the WDT reset contition somehow. We use the GPIO LED 0 - we set it to on if the reset source was WDT. Also, we want to read and reset MCUSR as early as possible. We do it from main(), and we then send the saved value where needed (init_log() and power_down()).
patterns: fibonacci-scaled step duration We have only three bits for pattern duration now, use Fibonacci-compressed values: instead of 0-7, use 0, 1, 2, 3, 5, 8, 13, and 21.
patterns: 3 bits for duration, 5 bits for mode I plan to use a single mode for encoding all three pwmleds: 2 bits for PWMLED 0 1 bit for PWMLED 1 2 bits for PWMLED 2
adc: use only active pwmleds, on-demand switching of other channels
pwm.c: channels running - visible from the outside Make the status of T/C1 visible from the outside, in order to make the on-demand ADC channel selection possible, and also to allow selecting the sleep modes in the main loop.
pwm.c: disable when not needed Timer/Counter 1 eats much power, especially with PLL clock. So let's try to disable it when no PWM channel is active.
ambient: log minima and maxima In order to be able to tune the ambient light sensor better, I made it to log the minimum and maximum values read for every three minutes or so. When the log buffer fills, start over only after the next off/on cycle.
pwmleds: less measurements per run With low-pass filters at the input of PWMLED ADC pins, it is now relatively stable and noise-free, so we can lower the number of readings to two. Hopefully this will not cause instability.
slow ADC inputs The fastest-repeated measurements are needed for PWM LEDs. OTOH, things like buttons, battery voltage, ambient lights, etc. can be read less frequently, and should be read in a deterministic time frame. So we will measure PWMLED current in the free-running mode (as fast as possible), and the other "slow" ADC inputs with each PATTERN_DIV-th timer tick.
ambient light sensor: configurable # of readings Set the # of readings to 1, and decrease the shift value for running average in order to get faster reaction.