extern struct ao_pad_query ao_pad_query; /* Last received QUERY from pad */
#ifdef AO_LCO_DRAG_RACE_BOX
-#define AO_LCO_BOX_DRAG 0 /* Box number to enable drag race mode (old LCO bits) */
-#define AO_LCO_BOX_FIRST AO_LCO_BOX_DRAG
+# define AO_LCO_BOX_DRAG 0 /* Box number to enable drag race mode (old LCO bits) */
+# define AO_LCO_BOX_FIRST AO_LCO_BOX_DRAG
#else
-# define AO_LCO_LCO_VOLTAGE 0 /* Box number to show LCO voltage */
-# ifdef AO_LCO_HAS_INFO
-# define AO_LCO_INFO -3
+# ifdef AO_LCO_HAS_CONTRAST
+# define AO_LCO_CONTRAST -2
# ifndef AO_LCO_BOX_FIRST
-# define AO_LCO_BOX_FIRST AO_LCO_INFO
+# define AO_LCO_BOX_FIRST AO_LCO_CONTRAST
# endif
# endif
-# ifdef AO_LCO_HAS_BACKLIGHT
-# define AO_LCO_BACKLIGHT -2
-# ifndef AO_LCO_BOX_FIRST
-# define AO_LCO_BOX_FIRST AO_LCO_BACKLIGHT
-# endif
+# ifdef AO_LCO_HAS_BACKLIGHT_UI
+# define AO_LCO_BACKLIGHT -1
+# ifndef AO_LCO_BOX_FIRST
+# define AO_LCO_BOX_FIRST AO_LCO_BACKLIGHT
+# endif
# endif
-# ifdef AO_LCO_HAS_CONTRAST
-# define AO_LCO_CONTRAST -1
+# if AO_LCO_HAS_LCO_INFO
+# define AO_LCO_LCO_INFO 0 /* Box number to show LCO info */
# ifndef AO_LCO_BOX_FIRST
-# define AO_LCO_BOX_FIRST AO_LCO_CONTRAST
+# define AO_LCO_BOX_FIRST AO_LCO_LCO_INFO
+# endif
+# else
+# define AO_LCO_LCO_VOLTAGE -1
+# ifndef AO_LCO_BOX_FIRST
+# define AO_LCO_BOX_FIRST AO_LCO_LCO_VOLTAGE
# endif
# endif
# ifndef AO_LCO_BOX_FIRST
-# define AO_LCO_BOX_FIRST AO_LCO_LCO_VOLTAGE
+# define AO_LCO_BOX_FIRST 1
# endif
#endif
-#define AO_LCO_PAD_VOLTAGE 0 /* Pad number to show box voltage */
-#define AO_LCO_PAD_RSSI -1 /* Pad number to show box RSSI */
-#define AO_LCO_PAD_FIRST AO_LCO_PAD_RSSI
+
+#ifdef AO_LCO_HAS_PAD_INFO
+# define AO_LCO_PAD_INFO 0 /* Pad number to show box info */
+# define AO_LCO_PAD_FIRST AO_LCO_PAD_INFO
+#else
+# define AO_LCO_PAD_VOLTAGE 0 /* Pad number to show box voltage */
+# define AO_LCO_PAD_RSSI -1 /* Pad number to show box RSSI */
+# define AO_LCO_PAD_FIRST AO_LCO_PAD_RSSI
+#endif
static inline bool
ao_lco_box_pseudo(int16_t box)
case AO_LCO_BACKLIGHT:
return true;
#endif
-#ifdef AO_LCO_INFO
- case AO_LCO_INFO:
+#ifdef AO_LCO_LCO_INFO
+ case AO_LCO_LCO_INFO:
return true;
#endif
default:
ao_lco_pad_pseudo(int8_t pad)
{
switch (pad) {
+#ifdef AO_LCO_PAD_VOLTAGE
case AO_LCO_PAD_VOLTAGE:
return true;
+#endif
+#ifdef AO_LCO_PAD_RSSI
case AO_LCO_PAD_RSSI:
return true;
+#endif
+#ifdef AO_LCO_PAD_INFO
+ case AO_LCO_PAD_INFO:
+ return true;
+#endif
default:
return false;
}
#include <ao_st7565.h>
#include <ao_adc_single.h>
#include <ao_pwm.h>
+#include <limits.h>
#define WIDTH AO_ST7565_WIDTH
#define HEIGHT AO_ST7565_HEIGHT
#define BACKLIGHT_HEIGHT 20
#define BACKLIGHT_VALUE_X 64
#define BACKLIGHT_VALUE_Y (BACKLIGHT_Y + BACKLIGHT_HEIGHT + SMALL_FONT.ascent + 3)
-#define INFO_START_Y ((int16_t) (SMALL_FONT.ascent + 2))
-#define INFO_STEP_Y ((int16_t) (SMALL_FONT.ascent + 3))
+#define INFO_FONT TINY_FONT
+#define INFO_START_Y ((int16_t) (INFO_FONT.ascent + 2))
+#define INFO_STEP_Y ((int16_t) (INFO_FONT.ascent + 2))
#define AO_LCO_DRAG_RACE_START_TIME AO_SEC_TO_TICKS(5)
#define AO_LCO_DRAG_RACE_STOP_TIME AO_SEC_TO_TICKS(2)
static uint8_t ao_lco_display_mutex;
+static uint8_t ao_sample_data;
+static struct ao_data ao_data_cur;
+
static void
_ao_center_text(int16_t x, int16_t y, const struct ao_font *font, const char *str)
{
}
static void
-_ao_lco_show_voltage(uint16_t decivolts, const char *label)
+_ao_format_voltage(char *str, size_t size, uint16_t decivolts)
{
- char str[7];
-
- PRINTD("voltage %d\n", decivolts);
- _ao_center_text(WIDTH/2, LABEL_Y, &SMALL_FONT, label);
- snprintf(str, sizeof(str), "%d.%d", decivolts / 10, decivolts % 10);
- _ao_center_text(WIDTH/2, VALUE_Y, &BIG_FONT, str);
-}
-
-static void
-_ao_lco_batt_voltage(void)
-{
- struct ao_adc packet;
- int16_t decivolt;
-
- ao_adc_single_get(&packet);
- decivolt = ao_battery_decivolt(packet.v_batt);
- _ao_lco_show_voltage((uint16_t) decivolt, "LCO Battery");
- ao_st7565_update(&fb);
+ snprintf(str, size, "%d.%d", decivolts / 10, decivolts % 10);
}
+#if AO_LCO_HAS_CONTRAST
static void
_ao_lco_show_contrast(void)
{
snprintf(buf, sizeof(buf), "%d %%", brightness * 100 / AO_LCO_MAX_CONTRAST);
_ao_center_text(WIDTH/2, CONTRAST_VALUE_Y, &SMALL_FONT, buf);
}
+#endif
+#if AO_LCO_HAS_BACKLIGHT_UI
static void
_ao_lco_show_backlight(void)
{
snprintf(buf, sizeof(buf), "%ld %%", backlight * 100 / AO_LCO_MAX_BACKLIGHT);
_ao_center_text(WIDTH/2, BACKLIGHT_VALUE_Y, &SMALL_FONT, buf);
}
+#endif
static int16_t info_y;
va_start(a, format);
vsnprintf(buf, sizeof(buf), format, a);
va_end(a);
- ao_text(&fb, &SMALL_FONT, 0, info_y, buf, AO_BLACK, AO_COPY);
+ ao_text(&fb, &INFO_FONT, 0, info_y, buf, AO_BLACK, AO_COPY);
info_y += INFO_STEP_Y;
}
static void
-_ao_lco_show_info(void)
+_ao_lco_show_lco_info(void)
{
- info_y = INFO_START_Y;
+ char battery[7];
+ int16_t decivolt;
+
ao_logo_poly(&fb, &show_transform, AO_BLACK, AO_COPY);
+
+ decivolt = ao_battery_decivolt(ao_data_cur.adc.v_batt);
+ _ao_format_voltage(battery, sizeof(battery), (uint16_t) decivolt);
+
+ info_y = INFO_START_Y;
_ao_lco_info("%s", ao_product);
_ao_lco_info("Serial: %d", ao_serial_number);
+ _ao_lco_info("Battery: %sV", battery);
_ao_lco_info("Version: %s", ao_version);
_ao_lco_info("Callsign: %s", ao_config.callsign);
_ao_lco_info("Frequency: %ld.%03d",
(int) (ao_config.frequency % 1000));
}
+static uint8_t
+popcount(uint32_t value)
+{
+ uint8_t count = 0;
+ while(value != 0) {
+ count += value & 1;
+ value >>= 1;
+ }
+ return count;
+}
+
+static void
+_ao_lco_show_pad_info(void)
+{
+ char pad_battery[7];
+
+ ao_logo_poly(&fb, &show_transform, AO_BLACK, AO_COPY);
+ info_y = INFO_START_Y;
+ _ao_lco_info("Bank: %d", ao_lco_box);
+ if (!(ao_lco_valid[ao_lco_box] & AO_LCO_VALID_LAST)) {
+ _ao_lco_info("Contact lost");
+ _ao_lco_info("Last RSSI: %ddBm", ao_radio_cmac_last_rssi);
+ } else {
+ _ao_lco_info("Total pads: %d", popcount(ao_pad_query.channels));
+ _ao_lco_info("RSSI: %ddBm", ao_radio_cmac_rssi);
+ _ao_format_voltage(pad_battery, sizeof(pad_battery), ao_pad_query.battery);
+ _ao_lco_info("Battery: %sV", pad_battery);
+ _ao_lco_info("Arming switch: %s", ao_pad_query.arm_status ? "On" : "Off");
+ }
+}
+
+#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_lco_show_rssi(void)
+ao_auto_backlight(int16_t als_min, int16_t als_max)
{
- char label[20];
- int16_t width;
- snprintf(label, sizeof(label), "Bank %d RSSI", ao_lco_box);
- width = ao_text_width(&SMALL_FONT, label);
- ao_text(&fb, &SMALL_FONT, VALUE_LABEL_X - width / 2, LABEL_Y, label, AO_BLACK, AO_COPY);
- if (!(ao_lco_valid[ao_lco_box] & AO_LCO_VALID_LAST))
- strcpy(label, "---");
- else
- snprintf(label, sizeof(label), "%d", ao_radio_cmac_rssi);
- width = ao_text_width(&VOLT_FONT, label);
- ao_text(&fb, &VOLT_FONT, VALUE_LABEL_X - width / 2, VALUE_Y, label, AO_BLACK, AO_COPY);
+ 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_show_pad_battery(void)
+ao_lco_data(void)
{
- char label[20];
- snprintf(label, sizeof(label), "Bank %d Battery", ao_lco_box);
- _ao_lco_show_voltage(ao_pad_query.battery, label);
+ 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;
+ }
+ }
}
void
ao_mutex_get(&ao_lco_display_mutex);
ao_rect(&fb, 0, 0, WIDTH, HEIGHT, AO_WHITE, AO_COPY);
switch (ao_lco_box) {
- case AO_LCO_LCO_VOLTAGE:
- _ao_lco_batt_voltage();
- break;
+#if AO_LCO_HAS_CONTRAST
case AO_LCO_CONTRAST:
_ao_lco_show_contrast();
break;
+#endif
+#if AO_LCO_HAS_BACKLIGHT_UI
case AO_LCO_BACKLIGHT:
_ao_lco_show_backlight();
break;
- case AO_LCO_INFO:
- _ao_lco_show_info();
+#endif
+ case AO_LCO_LCO_INFO:
+ _ao_lco_show_lco_info();
break;
default:
switch (ao_lco_pad) {
- case AO_LCO_PAD_RSSI:
- _ao_lco_show_rssi();
- break;
- case AO_LCO_PAD_VOLTAGE:
- _ao_lco_show_pad_battery();
+ case AO_LCO_PAD_INFO:
+ _ao_lco_show_pad_info();
break;
default:
_ao_lco_show_pad(ao_lco_pad);
}
+#if AO_LCO_HAS_CONTRAST
void
ao_lco_set_contrast(int32_t contrast)
{
{
return (int32_t) ao_st7565_get_brightness();
}
+#endif
+#if AO_LCO_HAS_BACKLIGHT
static uint16_t ao_backlight;
void
{
return (int32_t) ao_backlight;
}
+#endif
static struct ao_task ao_lco_drag_task;
static struct ao_task ao_lco_input_task;
static struct ao_task ao_lco_monitor_task;
+static struct ao_task ao_lco_data_task;
static struct ao_task ao_lco_arm_warn_task;
static struct ao_task ao_lco_igniter_status_task;
ao_lco_init(void)
{
ao_add_task(&ao_lco_monitor_task, ao_lco_main, "lco monitor");
+ ao_add_task(&ao_lco_data_task, ao_lco_data, "lco data");
#if DEBUG
ao_cmd_register(&ao_lco_cmds[0]);
#endif
#define AO_BUTTON_0 1
#define AO_BUTTON_DRAG_SELECT 1
-#define AO_BUTTON_1_PORT &stm_gpioc
-#define AO_BUTTON_1 0
+#define AO_BUTTON_1_PORT &stm_gpiod
+#define AO_BUTTON_1 2
#define AO_BUTTON_SPARE1 2
#define AO_BUTTON_2_PORT &stm_gpiob
/* ADC */
-struct ao_adc {
- int16_t v_batt;
-};
-
-#define AO_ADC_DUMP(p) \
- printf("batt: %5d\n", (p)->v_batt)
+#define AO_DATA_RING 8
-#define HAS_ADC_SINGLE 1
+#define HAS_ADC 1
#define HAS_ADC_TEMP 0
#define HAS_BATTERY_REPORT 1
#define AO_ADC_V_BATT_PORT (&stm_gpioa)
#define AO_ADC_V_BATT_PIN 2
+#define AO_ADC_V_ALS 10
+#define AO_ADC_V_ALS_PORT (&stm_gpioc)
+#define AO_ADC_V_ALS_PIN 0
+
#define AO_ADC_PIN0_PORT AO_ADC_V_BATT_PORT
#define AO_ADC_PIN0_PIN AO_ADC_V_BATT_PIN
+#define AO_ADC_PIN1_PORT AO_ADC_V_ALS_PORT
+#define AO_ADC_PIN1_PIN AO_ADC_V_ALS_PIN
+
#define AO_ADC_SQ1 AO_ADC_V_BATT
+#define AO_ADC_SQ2 AO_ADC_V_ALS
-#define AO_NUM_ADC 1
+#define AO_NUM_ADC 2
+
+struct ao_adc {
+ union {
+ struct {
+ int16_t v_batt;
+ int16_t v_als;
+ };
+ int16_t v_vals[AO_NUM_ADC];
+ };
+};
+
+#define AO_ADC_DUMP(p) \
+ printf("batt: %5d als %5d\n", (p)->adc.v_batt, (p)->adc.v_als)
/*
* Voltage divider on ADC battery sampler
#define AO_ADC_REFERENCE_DV 33
#define AO_LCO_SEARCH_API
-#define AO_LCO_HAS_CONTRAST 1
-#define AO_LCO_MIN_CONTRAST 0
-#define AO_LCO_MAX_CONTRAST 63
-#define AO_LCO_CONTRAST_STEP 1
+
+//#define AO_LCO_HAS_CONTRAST 1
+//#define AO_LCO_MIN_CONTRAST 0
+//#define AO_LCO_MAX_CONTRAST 63
+//#define AO_LCO_CONTRAST_STEP 1
#define AO_LCO_HAS_BACKLIGHT 1
#define AO_LCO_MIN_BACKLIGHT 0
#define AO_LCO_MAX_BACKLIGHT 65535
#define AO_LCO_BACKLIGHT_STEP 771
-#define AO_LCO_HAS_INFO 1
+#define AO_LCO_HAS_LCO_INFO 1
#define AO_LCO_MIN_INFO_PAGE 0
#define AO_LCO_MAX_INFO_PAGE 0
+#define AO_LCO_HAS_PAD_INFO 1
+
/*
* LCD Backlight via PWM.
*