Provide a UI for setting the LCD contrast.
Signed-off-by: Keith Packard <keithp@keithp.com>
(0 << 6))
void
-ao_lco_show_box(uint16_t box)
+ao_lco_show_box(int16_t box)
{
ao_mutex_get(&ao_lco_display_mutex);
if (box == AO_LCO_BOX_DRAG) {
#endif
extern uint8_t ao_lco_pad; /* Currently selected pad */
-extern uint16_t ao_lco_box; /* Currently selected box */
+extern int16_t ao_lco_box; /* Currently selected box */
extern uint8_t ao_lco_armed; /* armed mode active */
extern uint8_t ao_lco_firing; /* fire button pressed */
#define AO_LCO_BOX_FIRST AO_LCO_BOX_DRAG
#else
#define AO_LCO_LCO_VOLTAGE 0 /* Box number to show LCO voltage */
-#define AO_LCO_BOX_FIRST AO_LCO_LCO_VOLTAGE
+# ifdef AO_LCO_HAS_CONTRAST
+# define AO_LCO_CONTRAST -1
+# define AO_LCO_BOX_FIRST AO_LCO_CONTRAST
+# else
+# define AO_LCO_BOX_FIRST AO_LCO_LCO_VOLTAGE
+# endif
#endif
#define AO_LCO_PAD_VOLTAGE 0 /* Pad number to show box voltage */
static inline bool
-ao_lco_box_pseudo(uint16_t box)
+ao_lco_box_pseudo(int16_t box)
{
switch (box) {
#ifdef AO_LCO_LCO_VOLTAGE
#ifdef AO_LCO_DRAG_RACE_BOX
case AO_LCO_BOX_DRAG:
return true;
+#endif
+#ifdef AO_LCO_CONTRAST
+ case AO_LCO_CONTRAST:
+ return true;
#endif
default:
return false;
}
}
-extern uint16_t ao_lco_min_box, ao_lco_max_box;
+extern int16_t ao_lco_min_box, ao_lco_max_box;
#define AO_LCO_MASK_SIZE(n) (((n) + 7) >> 3)
#define AO_LCO_MASK_ID(n) ((n) >> 3)
ao_lco_update(void);
uint8_t
-ao_lco_pad_present(uint16_t box, uint8_t pad);
+ao_lco_pad_present(int16_t box, uint8_t pad);
uint8_t
-ao_lco_pad_first(uint16_t box);
+ao_lco_pad_first(int16_t box);
void
ao_lco_set_pad(uint8_t new_pad);
ao_lco_step_pad(int8_t dir);
void
-ao_lco_set_box(uint16_t new_box);
+ao_lco_set_box(int16_t new_box);
void
ao_lco_step_box(int8_t dir);
ao_lco_show_pad(uint8_t pad);
void
-ao_lco_show_box(uint16_t box);
+ao_lco_show_box(int16_t box);
void
ao_lco_show(void);
ao_lco_init(void);
uint8_t
-ao_lco_box_present(uint16_t box);
+ao_lco_box_present(int16_t box);
+
+#ifdef AO_LCO_HAS_CONTRAST
+void
+ao_lco_set_contrast(int16_t contrast);
+
+int16_t
+ao_lco_get_contrast(void);
+#endif
#ifdef AO_LCO_SEARCH_API
ao_lco_search_start(void);
void
-ao_lco_search_box_check(uint16_t box);
+ao_lco_search_box_check(int16_t box);
void
-ao_lco_search_box_present(uint16_t box);
+ao_lco_search_box_present(int16_t box);
void
ao_lco_search_done(void);
uint8_t ao_lco_debug;
uint8_t ao_lco_pad;
-uint16_t ao_lco_box;
+int16_t ao_lco_box;
uint8_t ao_lco_armed; /* arm active */
uint8_t ao_lco_firing; /* fire active */
-uint16_t ao_lco_min_box, ao_lco_max_box;
+int16_t ao_lco_min_box, ao_lco_max_box;
uint8_t ao_lco_pretending;
}
uint8_t
-ao_lco_pad_present(uint16_t box, uint8_t pad)
+ao_lco_pad_present(int16_t box, uint8_t pad)
{
/* voltage measurement is always valid */
if (pad == AO_LCO_PAD_VOLTAGE)
}
uint8_t
-ao_lco_pad_first(uint16_t box)
+ao_lco_pad_first(int16_t box)
{
uint8_t pad;
}
static uint8_t
-ao_lco_get_channels(uint16_t box, struct ao_pad_query *query)
+ao_lco_get_channels(int16_t box, struct ao_pad_query *query)
{
int8_t r;
- r = ao_lco_query(box, query, &ao_lco_tick_offset[box]);
+ r = ao_lco_query((uint16_t) box, query, &ao_lco_tick_offset[box]);
if (r == AO_RADIO_CMAC_OK) {
ao_lco_channels[box] = query->channels;
ao_lco_valid[box] = AO_LCO_VALID_LAST | AO_LCO_VALID_EVER;
}
static void
-ao_lco_box_set_present(uint16_t box)
+ao_lco_box_set_present(int16_t box)
{
if (box < ao_lco_min_box)
ao_lco_min_box = box;
}
void
-ao_lco_set_box(uint16_t new_box)
+ao_lco_set_box(int16_t new_box)
{
ao_lco_box = new_box;
if (!ao_lco_box_pseudo(ao_lco_box)) {
{
int16_t new_pad;
+#ifdef AO_LCO_HAS_CONTRAST
+ if (ao_lco_box == AO_LCO_CONTRAST) {
+ int16_t contrast = ao_lco_get_contrast();
+
+ contrast += (int16_t) (dir * AO_LCO_CONTRAST_STEP);
+ if (contrast < AO_LCO_MIN_CONTRAST)
+ contrast = AO_LCO_MIN_CONTRAST;
+ if (contrast > AO_LCO_MAX_CONTRAST)
+ contrast = AO_LCO_MAX_CONTRAST;
+ ao_lco_set_contrast(contrast);
+ }
+#endif
new_pad = (int16_t) ao_lco_pad;
do {
new_pad += dir;
}
uint8_t
-ao_lco_box_present(uint16_t box)
+ao_lco_box_present(int16_t box)
{
if (ao_lco_box_pseudo(box))
return 1;
void
ao_lco_step_box(int8_t dir)
{
- int32_t new_box = (int32_t) ao_lco_box;
+ int16_t new_box = ao_lco_box;
do {
new_box += dir;
if (new_box > ao_lco_max_box)
new_box = AO_LCO_BOX_FIRST;
+#ifdef AO_LCO_HAS_CONTRAST
+ else if (new_box < AO_LCO_CONTRAST)
+#else
else if (new_box < 0)
+#endif
new_box = ao_lco_max_box;
if (new_box == ao_lco_box)
break;
- } while (!ao_lco_box_present((uint16_t) new_box));
- PRINTD("New box %ld\n", new_box);
- ao_lco_set_box((uint16_t) new_box);
+ } while (!ao_lco_box_present(new_box));
+ PRINTD("New box %d\n", new_box);
+ ao_lco_set_box(new_box);
}
void
if (ao_lco_armed) {
#if AO_LCO_DRAG
if (ao_lco_drag_race) {
- uint16_t box;
+ int16_t box;
for (box = ao_lco_min_box; box <= ao_lco_max_box; box++)
if (ao_lco_selected[box])
{
int8_t r;
int8_t try;
- uint16_t box;
+ int16_t box;
uint16_t boxes = 0;
ao_lco_box_reset_present();
#endif
for (try = 0; try < 3; try++) {
ao_lco_tick_offset[box] = 0;
- r = ao_lco_query(box, &ao_pad_query, &ao_lco_tick_offset[box]);
+ r = ao_lco_query((uint16_t) box, &ao_pad_query, &ao_lco_tick_offset[box]);
PRINTD("box %d result %d offset %d\n", box, r, ao_lco_tick_offset[box]);
if (r == AO_RADIO_CMAC_OK) {
++boxes;
void
ao_lco_pretend(void)
{
- uint16_t box;
+ int16_t box;
ao_lco_pretending = 1;
ao_lco_min_box = 1;
void
ao_lco_monitor(void)
{
- AO_TICK_TYPE delay;
- uint16_t box;
+ AO_TICK_TYPE delay;
+ int16_t box;
for (;;) {
PRINTD("monitor armed %d firing %d\n",
PRINTD("Arming box %d pads %x\n",
box, ao_lco_selected[box]);
if (ao_lco_valid[box] & AO_LCO_VALID_EVER) {
- ao_lco_arm(box, ao_lco_selected[box], ao_lco_tick_offset[box]);
+ ao_lco_arm((uint16_t) box, ao_lco_selected[box], ao_lco_tick_offset[box]);
ao_delay(AO_MS_TO_TICKS(10));
}
}
}
void
-ao_lco_show_box(uint16_t box)
+ao_lco_show_box(int16_t box)
{
(void) box;
}
case AO_EVENT_BUTTON:
switch (event.unit) {
case AO_BUTTON_BOX:
- ao_lco_set_box((uint16_t) event.value);
+ ao_lco_set_box((int16_t) event.value);
ao_lco_set_armed(0);
break;
case AO_BUTTON_ARM:
ao_st7565_stop();
}
-static void
+static uint8_t brightness;
+
+void
ao_st7565_set_brightness(uint8_t val)
{
+ if (val > 63)
+ val = 63;
+ brightness = val;
ao_st7565_instruction_param(ST7565_ELECTRONIC_VOLUME_SET, val);
}
+uint8_t
+ao_st7565_get_brightness(void)
+{
+ return brightness;
+}
+
static bool setup_done;
static void
void
ao_st7565_update(struct ao_bitmap *bitmap);
+void
+ao_st7565_set_brightness(uint8_t val);
+
+uint8_t
+ao_st7565_get_brightness(void);
+
void
ao_st7565_init(void);
(0 << 6))
void
-ao_lco_show_box(uint16_t box)
+ao_lco_show_box(int16_t box)
{
ao_mutex_get(&ao_lco_display_mutex);
ao_seven_segment_set(AO_LCO_BOX_DIGIT_1, (uint8_t) (box % 10 | (ao_lco_drag_race << 4)));
ao_radio_cmac.h \
ao_cc1200_CC1200.h \
ao_cc1200.h \
+ ao_st7565.h \
ao_font.h \
ao_logo.h \
stm32f1.h
#define BIG_FONT BitstreamVeraSans_Roman_58_font
#define VOLT_FONT BitstreamVeraSans_Roman_58_font
+#define CONTRAST_FONT BitstreamVeraSans_Roman_58_font
#define SMALL_FONT BitstreamVeraSans_Roman_12_font
#define TINY_FONT BitstreamVeraSans_Roman_10_font
#define LOGO_FONT BenguiatGothicStd_Bold_26_font
#define FOUND_Y 63
#define FOUND_X 6
#define FOUND_WIDTH (WIDTH - 6)
+#define CONTRAST_LABEL_X 37
+#define CONTRAST_WIDTH 100
+#define CONTRAST_X (WIDTH - CONTRAST_WIDTH) / 2
+#define CONTRAST_Y 20
+#define CONTRAST_HEIGHT 20
#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 void
-_ao_lco_show_box(uint16_t box)
+_ao_lco_show_box(int16_t box)
{
char str[7];
ao_st7565_update(&fb);
}
+static void
+_ao_lco_show_contrast(void)
+{
+ uint8_t brightness = ao_st7565_get_brightness();
+ int16_t contrast = (int16_t) (brightness * CONTRAST_WIDTH / AO_LCO_MAX_CONTRAST);
+
+ ao_text(&fb, &SMALL_FONT, CONTRAST_LABEL_X, LABEL_Y, "Contrast", AO_BLACK, AO_COPY);
+ ao_rect(&fb, CONTRAST_X, CONTRAST_Y, contrast, CONTRAST_HEIGHT, AO_BLACK, AO_COPY);
+}
+
void
ao_lco_show(void)
{
ao_rect(&fb, 0, 0, WIDTH, HEIGHT, AO_WHITE, AO_COPY);
if (ao_lco_box == AO_LCO_LCO_VOLTAGE) {
_ao_lco_batt_voltage();
+ } else if (ao_lco_box == AO_LCO_CONTRAST) {
+ _ao_lco_show_contrast();
} else if (ao_lco_pad == AO_LCO_PAD_VOLTAGE) {
_ao_lco_show_voltage(ao_pad_query.battery, "Pad battery");
} else {
}
+void
+ao_lco_set_contrast(int16_t contrast)
+{
+ ao_st7565_set_brightness((uint8_t) contrast);
+}
+
+int16_t
+ao_lco_get_contrast(void)
+{
+ return (int16_t) ao_st7565_get_brightness();
+}
+
static struct ao_task ao_lco_drag_task;
static void
}
void
-ao_lco_search_box_check(uint16_t box)
+ao_lco_search_box_check(int16_t box)
{
if (box > 0)
- ao_rect(&fb, SCAN_X, SCAN_Y, (int16_t) box, SCAN_HEIGHT, AO_BLACK, AO_COPY);
+ ao_rect(&fb, SCAN_X, SCAN_Y, box, SCAN_HEIGHT, AO_BLACK, AO_COPY);
ao_st7565_update(&fb);
}
void
-ao_lco_search_box_present(uint16_t box)
+ao_lco_search_box_present(int16_t box)
{
char str[8];
if (found_x < FOUND_WIDTH)
ao_st7565_update(&fb);
}
-static void
-ao_lco_batt_voltage(void)
-{
- ao_rect(&fb, 0, 0, WIDTH, HEIGHT, AO_WHITE, AO_COPY);
- _ao_lco_batt_voltage();
- ao_st7565_update(&fb);
- ao_delay(AO_MS_TO_TICKS(1000));
-}
-
static void
ao_lco_main(void)
{
ao_lco_display_test();
- ao_lco_batt_voltage();
ao_lco_search();
ao_add_task(&ao_lco_input_task, ao_lco_input, "lco input");
ao_add_task(&ao_lco_arm_warn_task, ao_lco_arm_warn, "lco arm warn");
#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
#endif /* _AO_PINS_H_ */
#include <ao_adc_single.h>
#include <ao_st7565.h>
+#define WIDTH AO_ST7565_WIDTH
+#define HEIGHT AO_ST7565_HEIGHT
+#define STRIDE AO_BITMAP_STRIDE(WIDTH)
+
+static uint32_t image[STRIDE * HEIGHT];
+
+static struct ao_bitmap fb = {
+ .base = image,
+ .stride = STRIDE,
+ .width = WIDTH,
+ .height = HEIGHT,
+ .damage = AO_BOX_INIT,
+};
+
+static void
+ao_st7565_test(void)
+{
+ ao_rect(&fb, 0, 0, WIDTH, HEIGHT, AO_WHITE, AO_COPY);
+ ao_st7565_update(&fb);
+ ao_text(&fb, &BitstreamVeraSans_Roman_24_font,
+ 0, 20, "hello world", AO_BLACK, AO_COPY);
+ ao_st7565_update(&fb);
+}
+
+static int16_t x1 = 32, _y1 = 10, x2 = 32, y2 = 40;
+static int16_t dx1 = 2, dy1 = 2, dx2 = -2, dy2 = -1;
+
+#define bounds(v,m,M,d) \
+ if (v < m) { \
+ v = m + m - v; \
+ d = -d; \
+ } else if (v > M) { \
+ v = M - (v - M); \
+ d = -d; \
+ }
+
+static void
+ao_st7565_line(void)
+{
+ int i;
+
+ for (i = 0; i < 100; i++) {
+ ao_rect(&fb, 0, 0, WIDTH, HEIGHT, AO_WHITE, AO_COPY);
+ ao_line(&fb, x1, _y1, x2, y2, AO_BLACK, AO_COPY);
+ ao_st7565_update(&fb);
+ x1 += dx1;
+ _y1 += dy1;
+ x2 += dx2;
+ y2 += dy2;
+ printf("%d,%d - %d,%d\n", x1, _y1, x2, y2);
+ fflush(stdout);
+ bounds(x1, 0, WIDTH, dx1);
+ bounds(x2, 0, WIDTH, dx2);
+ bounds(_y1, 0, HEIGHT, dy1);
+ bounds(y2, 0, HEIGHT, dy2);
+ ao_delay(AO_MS_TO_TICKS(200));
+ }
+}
+
+static const float pad_volts = 12.3f;
+static const float lco_volts = 4.1f;
+static const int rssi = -30;
+
+static int boxes[] = { 1, 2, 3, 5, 8, 11, 13, 17, 19, 23, 29, 31, 37, 62, 97 };
+
+//static int max_box = 97;
+
+#define ARRAYSIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+static bool
+valid_box(int box)
+{
+ size_t i;
+ if (box == 0)
+ return true;
+ for (i = 0; i < ARRAYSIZE(boxes); i++)
+ if (boxes[i] == box)
+ return true;
+ return false;
+}
+
+#if 0
+static void
+next_box(void)
+{
+ for (int n = box_number + 1; n <= max_box; n++)
+ if (valid_box(n)) {
+ box_number = n;
+ return;
+ }
+ box_number = 0;
+}
+
+static void
+prev_box(void)
+{
+ for (int n = box_number - 1; n >= 0; n--)
+ if (valid_box(n)) {
+ box_number = n;
+ return;
+ }
+ box_number = max_box;
+}
+#endif
+
+static const struct ao_transform logo_transform = {
+ .x_scale = 48, .x_off = 2,
+ .y_scale = 48, .y_off = 0,
+};
+
+#define BIG_FONT BitstreamVeraSans_Roman_58_font
+#define VOLT_FONT BitstreamVeraSans_Roman_58_font
+#define SMALL_FONT BitstreamVeraSans_Roman_12_font
+#define TINY_FONT BitstreamVeraSans_Roman_10_font
+#define LOGO_FONT BenguiatGothicStd_Bold_26_font
+
+#define LABEL_Y (int16_t) (SMALL_FONT.ascent)
+#define VALUE_Y (int16_t) (LABEL_Y + BIG_FONT.ascent + 5)
+#define BOX_X 2
+#define PAD_X 90
+#define BOX_LABEL_X 30
+#define VOLT_LABEL_X 25
+#define RSSI_LABEL_X 15
+#define PAD_LABEL_X 95
+#define SEP_X (PAD_X - 8)
+#define SCAN_X (WIDTH - 100) / 2
+#define SCAN_Y 50
+#define SCAN_HEIGHT 3
+#define FOUND_Y 63
+#define FOUND_X 6
+#define FOUND_WIDTH 17
+#define MAX_VALID (WIDTH / FOUND_WIDTH)
+
+static int16_t box_number = 88;
+static int16_t pad_number = 8;
+
+static void
+ao_st7565_poly(void)
+{
+ int16_t scan_number;
+ char str[8];
+ int i;
+ int v;
+ int last_box;
+ int16_t b;
+
+ for (scan_number = 0; scan_number < 100; scan_number++) {
+ ao_rect(&fb, 0, 0, WIDTH, HEIGHT, AO_WHITE, AO_COPY);
+ ao_logo(&fb, &logo_transform, &LOGO_FONT, AO_BLACK, AO_COPY);
+ if (scan_number) {
+ ao_rect(&fb, SCAN_X, SCAN_Y, (int16_t) scan_number, SCAN_HEIGHT, AO_BLACK, AO_COPY);
+ b = 0;
+ v = 0;
+ last_box = 0;
+ for (i = scan_number; i > 1; i--) {
+ if (valid_box(i)) {
+ if (!last_box)
+ last_box = i;
+ v++;
+ if (v == MAX_VALID)
+ break;
+ }
+ }
+ for (; i <= scan_number; i++) {
+ if (valid_box(i)) {
+ sprintf(str, "%02d%s", i, i == last_box ? "" : ",");
+ ao_text(&fb, &TINY_FONT, (int16_t) (FOUND_X + FOUND_WIDTH * b),
+ FOUND_Y, str, AO_BLACK, AO_COPY);
+ b++;
+ }
+ }
+ }
+ ao_st7565_update(&fb);
+ ao_delay(AO_MS_TO_TICKS(50));
+ }
+ ao_rect(&fb, 0, 0, WIDTH, HEIGHT, AO_WHITE, AO_COPY);
+ switch (box_number) {
+ case 0:
+ sprintf(str, "%4.1f", lco_volts);
+ ao_text(&fb, &VOLT_FONT, BOX_X, VALUE_Y, str, AO_BLACK, AO_COPY);
+ ao_text(&fb, &SMALL_FONT, VOLT_LABEL_X, LABEL_Y, "LCO Battery", AO_BLACK, AO_COPY);
+ break;
+ default:
+ switch (pad_number) {
+ case -1:
+ sprintf(str, "%4.1f", pad_volts);
+ ao_text(&fb, &VOLT_FONT, BOX_X, VALUE_Y, str, AO_BLACK, AO_COPY);
+ ao_text(&fb, &SMALL_FONT, VOLT_LABEL_X, LABEL_Y, "Pad Battery", AO_BLACK, AO_COPY);
+ break;
+ case 0:
+ sprintf(str, "%4d", rssi);
+ ao_text(&fb, &VOLT_FONT, BOX_X, VALUE_Y, str, AO_BLACK, AO_COPY);
+ ao_text(&fb, &SMALL_FONT, RSSI_LABEL_X, LABEL_Y, "Signal Strength", AO_BLACK, AO_COPY);
+ break;
+ default:
+ sprintf(str, "%02d", box_number);
+ ao_text(&fb, &BIG_FONT, BOX_X, VALUE_Y, str, AO_BLACK, AO_COPY);
+ ao_text(&fb, &SMALL_FONT, BOX_LABEL_X, LABEL_Y, "Box", AO_BLACK, AO_COPY);
+
+ sprintf(str, "%d", pad_number);
+ ao_text(&fb, &BIG_FONT, PAD_X, VALUE_Y, str, AO_BLACK, AO_COPY);
+ ao_text(&fb, &SMALL_FONT, PAD_LABEL_X, LABEL_Y, "Pad", AO_BLACK, AO_COPY);
+
+ ao_rect(&fb, SEP_X, 0, 2, HEIGHT, AO_BLACK, AO_COPY);
+ }
+ break;
+ }
+ ao_st7565_update(&fb);
+}
+
+const struct ao_cmds ao_st7565_cmds[] = {
+ { ao_st7565_test, "g\0Test ST7565 display" },
+ { ao_st7565_line, "l\0Draw lines" },
+ { ao_st7565_poly, "p\0Draw polygon" },
+ { 0, NULL },
+};
+
int
main(void)
{
ao_lco_init();
ao_lco_cmd_init();
+// ao_cmd_register(ao_st7565_cmds);
+
ao_led_off(LEDS_AVAILABLE);
ao_start_scheduler();