+#define AO_LCO_DIM_BACKLIGHT (AO_LCO_MIN_BACKLIGHT + 3 * AO_LCO_BACKLIGHT_STEP)
+#define AO_AUTO_BACKLIGHT_RANGE (AO_LCO_MAX_BACKLIGHT - AO_LCO_DIM_BACKLIGHT)
+#define AO_AUTO_BACKLIGHT_GAP AO_ADC_MAX / 6
+
+static struct {
+ int16_t v_als;
+ int32_t backlight;
+} ao_lco_backlight_map[] = {
+ { .v_als = AO_ADC_MAX / 6, .backlight = AO_LCO_DIM_BACKLIGHT },
+ { .v_als = AO_ADC_MAX / 3, .backlight = (AO_LCO_MAX_BACKLIGHT - AO_LCO_MIN_BACKLIGHT) / 2 },
+ { .v_als = AO_ADC_MAX / 2, .backlight = AO_LCO_MAX_BACKLIGHT },
+ { .v_als = AO_ADC_MAX * 3 / 4, .backlight = 0 },
+};
+
+#define NUM_BACKLIGHT_MAP sizeof(ao_lco_backlight_map)/sizeof(ao_lco_backlight_map[0])
+
+static unsigned ao_backlight_prev = NUM_BACKLIGHT_MAP - 1;
+
+static void
+ao_auto_backlight(int16_t als_min, int16_t als_max)
+{
+ unsigned ao_backlight;
+
+ PRINTD("ao_auto_backlight min %d max %d\n", als_min, als_max);
+ ao_backlight = ao_backlight_prev;
+ while (als_min > ao_lco_backlight_map[ao_backlight].v_als + AO_AUTO_BACKLIGHT_GAP) {
+ if (ao_backlight == NUM_BACKLIGHT_MAP - 1)
+ break;
+ ao_backlight++;
+ }
+ while (als_max < ao_lco_backlight_map[ao_backlight].v_als - AO_AUTO_BACKLIGHT_GAP) {
+ if (ao_backlight == 0)
+ return;
+ ao_backlight--;
+ }
+ if (ao_backlight != ao_backlight_prev)
+ {
+ PRINTD(" set backlight to %ld\n", ao_lco_backlight_map[ao_backlight].backlight);
+ ao_lco_set_backlight(ao_lco_backlight_map[ao_backlight].backlight);
+ ao_backlight_prev = ao_backlight;
+ }
+}
+
+#define AO_LCO_BACKLIGHT_INTERVAL AO_SEC_TO_TICKS(2)
+
+static void
+ao_lco_data(void)
+{
+ AO_TICK_TYPE backlight_tick = ao_time() + AO_LCO_BACKLIGHT_INTERVAL;
+ AO_TICK_TYPE now;
+ int16_t als_min = INT16_MAX;
+ int16_t als_max = INT16_MIN;
+
+ ao_timer_set_adc_interval(AO_MS_TO_TICKS(100));
+ for (;;) {
+ ao_sleep((void *) &ao_data_head);
+
+ while (ao_sample_data != ao_data_head) {
+ struct ao_data *ao_data;
+
+ /* Capture a sample */
+ ao_data = (struct ao_data *) &ao_data_ring[ao_sample_data];
+
+ ao_data_cur = *ao_data;
+ if (ao_data_cur.adc.v_als < als_min)
+ als_min = ao_data_cur.adc.v_als;
+ if (ao_data_cur.adc.v_als > als_max)
+ als_max = ao_data_cur.adc.v_als;
+ ao_sample_data = ao_data_ring_next(ao_sample_data);
+ }
+ now = ao_time();
+ if ((AO_TICK_SIGNED) (backlight_tick - now) < 0) {
+ backlight_tick = now + AO_LCO_BACKLIGHT_INTERVAL;
+ ao_auto_backlight(als_min, als_max);
+ als_min = INT16_MAX;
+ als_max = INT16_MIN;
+ }
+ }