#include "aic-eec.h"
/* ===== Global Variables: Input Panel ===== */
static lv_obj_t * btn_led_ind; /* Button status LED */
static lv_obj_t * btn_status_label; /* Button status text */
static lv_obj_t * adc_bar; /* ADC progress bar */
static lv_obj_t * adc_percent_label; /* ADC percentage */
static lv_obj_t * adc_voltage_label; /* ADC voltage */
/* ===== Global Variables: Output Panel ===== */
static lv_obj_t * led_inds[3]; /* LED indicators R,G,B */
static lv_obj_t * led_switches[2]; /* Switches for Red, Green */
static lv_obj_t * blue_slider; /* PWM slider for Blue */
static lv_obj_t * blue_duty_label; /* Blue duty % */
/* ===== Global Variables: Status Bar ===== */
static lv_obj_t * status_label;
/* ===== Forward Declarations ===== */
static void poll_timer_cb(lv_timer_t * t);
static void red_switch_cb(lv_event_t * e);
static void green_switch_cb(lv_event_t * e);
static void blue_slider_cb(lv_event_t * e);
static void all_on_cb(lv_event_t * e);
static void all_off_cb(lv_event_t * e);
/* ============================================================ */
/* CALLBACK FUNCTIONS */
/* ============================================================ */
/* Timer callback: poll Button + ADC every 50ms */
static void poll_timer_cb(lv_timer_t * t)
{
/* === [1] Read Button === */
int btn_raw = aic_gpio_button_read_raw(AIC_BTN_USER);
bool btn_pressed = (btn_raw == 0);
if (btn_pressed) {
lv_led_on(btn_led_ind);
lv_label_set_text(btn_status_label, "PRESSED");
lv_obj_set_style_text_color(btn_status_label,
lv_palette_main(LV_PALETTE_RED), 0);
} else {
lv_led_off(btn_led_ind);
lv_label_set_text(btn_status_label, "Released");
lv_obj_set_style_text_color(btn_status_label,
lv_palette_main(LV_PALETTE_GREEN), 0);
}
/* === [2] Read ADC === */
uint16_t adc_raw = aic_adc_read();
int percent = (int)((uint32_t)adc_raw * 100 / 4095);
float voltage = (float)adc_raw * 3.3f / 4095.0f;
lv_bar_set_value(adc_bar, percent, LV_ANIM_ON);
lv_label_set_text_fmt(adc_percent_label, "ADC: %d (%d%%)",
(int)adc_raw, percent);
lv_label_set_text_fmt(adc_voltage_label, "%.2f V", voltage);
/* === [3] Update Status Bar === */
lv_label_set_text_fmt(status_label,
"BTN=%s | ADC=%d | Blue=%d%%",
btn_pressed ? "PRESS" : "REL",
(int)adc_raw,
lv_slider_get_value(blue_slider));
}
/* Red LED Switch callback */
static void red_switch_cb(lv_event_t * e)
{
if (lv_event_get_code(e) != LV_EVENT_VALUE_CHANGED) return;
lv_obj_t * sw = lv_event_get_target(e);
bool on = lv_obj_has_state(sw, LV_STATE_CHECKED);
aic_gpio_led_set(AIC_LED_RED, on);
on ? lv_led_on(led_inds[0]) : lv_led_off(led_inds[0]);
}
/* Green LED Switch callback */
static void green_switch_cb(lv_event_t * e)
{
if (lv_event_get_code(e) != LV_EVENT_VALUE_CHANGED) return;
lv_obj_t * sw = lv_event_get_target(e);
bool on = lv_obj_has_state(sw, LV_STATE_CHECKED);
aic_gpio_led_set(AIC_LED_GREEN, on);
on ? lv_led_on(led_inds[1]) : lv_led_off(led_inds[1]);
}
/* Blue LED PWM Slider callback */
static void blue_slider_cb(lv_event_t * e)
{
if (lv_event_get_code(e) != LV_EVENT_VALUE_CHANGED) return;
lv_obj_t * slider = lv_event_get_target(e);
int duty = lv_slider_get_value(slider);
aic_gpio_pwm_set_duty(AIC_LED_BLUE, duty);
lv_led_set_brightness(led_inds[2], (uint8_t)(duty * 255 / 100));
lv_label_set_text_fmt(blue_duty_label, "%d%%", duty);
}
/* All ON callback */
static void all_on_cb(lv_event_t * e)
{
if (lv_event_get_code(e) != LV_EVENT_CLICKED) return;
/* Hardware */
aic_gpio_led_set(AIC_LED_RED, true);
aic_gpio_led_set(AIC_LED_GREEN, true);
aic_gpio_pwm_set_duty(AIC_LED_BLUE, 100);
/* UI: LEDs */
lv_led_on(led_inds[0]);
lv_led_on(led_inds[1]);
lv_led_set_brightness(led_inds[2], 255);
/* UI: Sync switches */
lv_obj_add_state(led_switches[0], LV_STATE_CHECKED);
lv_obj_add_state(led_switches[1], LV_STATE_CHECKED);
lv_slider_set_value(blue_slider, 100, LV_ANIM_ON);
lv_label_set_text(blue_duty_label, "100%");
}
/* All OFF callback */
static void all_off_cb(lv_event_t * e)
{
if (lv_event_get_code(e) != LV_EVENT_CLICKED) return;
/* Hardware */
aic_gpio_led_set(AIC_LED_RED, false);
aic_gpio_led_set(AIC_LED_GREEN, false);
aic_gpio_pwm_set_duty(AIC_LED_BLUE, 0);
/* UI: LEDs */
lv_led_off(led_inds[0]);
lv_led_off(led_inds[1]);
lv_led_set_brightness(led_inds[2], 0);
/* UI: Sync switches */
lv_obj_remove_state(led_switches[0], LV_STATE_CHECKED);
lv_obj_remove_state(led_switches[1], LV_STATE_CHECKED);
lv_slider_set_value(blue_slider, 0, LV_ANIM_ON);
lv_label_set_text(blue_duty_label, "0%");
}
/* ============================================================ */
/* HELPER: Create Input Panel */
/* ============================================================ */
static lv_obj_t * create_input_panel(lv_obj_t * parent)
{
lv_obj_t * panel = lv_obj_create(parent);
lv_obj_set_size(panel, LV_PCT(48), LV_PCT(100));
lv_obj_set_style_bg_color(panel, lv_color_hex(0x0f3460), 0);
lv_obj_set_flex_flow(panel, LV_FLEX_FLOW_COLUMN);
lv_obj_set_style_pad_all(panel, 8, 0);
lv_obj_set_style_pad_row(panel, 6, 0);
lv_obj_remove_flag(panel, LV_OBJ_FLAG_SCROLLABLE);
/* Panel Title */
lv_obj_t * lbl = lv_label_create(panel);
lv_label_set_text(lbl, "-- INPUT --");
lv_obj_set_style_text_color(lbl, lv_color_hex(0xFFAA00), 0);
/* Button Section */
lv_obj_t * btn_lbl = lv_label_create(panel);
lv_label_set_text(btn_lbl, "USER Button (SW2)");
lv_obj_set_style_text_color(btn_lbl, lv_color_hex(0xCCCCCC), 0);
lv_obj_t * btn_row = lv_obj_create(panel);
lv_obj_set_size(btn_row, LV_PCT(100), 35);
lv_obj_set_flex_flow(btn_row, LV_FLEX_FLOW_ROW);
lv_obj_set_flex_align(btn_row, LV_FLEX_ALIGN_START,
LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
lv_obj_set_style_bg_opa(btn_row, LV_OPA_TRANSP, 0);
lv_obj_set_style_border_width(btn_row, 0, 0);
lv_obj_set_style_pad_all(btn_row, 0, 0);
lv_obj_set_style_pad_column(btn_row, 10, 0);
lv_obj_remove_flag(btn_row, LV_OBJ_FLAG_SCROLLABLE);
btn_led_ind = lv_led_create(btn_row);
lv_led_set_color(btn_led_ind, lv_palette_main(LV_PALETTE_CYAN));
lv_obj_set_size(btn_led_ind, 25, 25);
lv_led_off(btn_led_ind);
btn_status_label = lv_label_create(btn_row);
lv_label_set_text(btn_status_label, "Released");
lv_obj_set_style_text_color(btn_status_label,
lv_palette_main(LV_PALETTE_GREEN), 0);
/* ADC Section */
lv_obj_t * adc_lbl = lv_label_create(panel);
lv_label_set_text(adc_lbl, "Potentiometer");
lv_obj_set_style_text_color(adc_lbl, lv_color_hex(0xCCCCCC), 0);
adc_bar = lv_bar_create(panel);
lv_obj_set_size(adc_bar, LV_PCT(95), 15);
lv_bar_set_range(adc_bar, 0, 100);
lv_bar_set_value(adc_bar, 0, LV_ANIM_OFF);
lv_obj_set_style_bg_color(adc_bar, lv_color_hex(0x333333), 0);
lv_obj_set_style_bg_color(adc_bar,
lv_palette_main(LV_PALETTE_CYAN), LV_PART_INDICATOR);
adc_percent_label = lv_label_create(panel);
lv_label_set_text(adc_percent_label, "ADC: 0 (0%)");
lv_obj_set_style_text_color(adc_percent_label,
lv_color_hex(0x00BFFF), 0);
adc_voltage_label = lv_label_create(panel);
lv_label_set_text(adc_voltage_label, "0.00 V");
lv_obj_set_style_text_color(adc_voltage_label,
lv_color_hex(0x00FF88), 0);
return panel;
}
/* ============================================================ */
/* HELPER: Create Output Panel */
/* ============================================================ */
static lv_obj_t * create_output_panel(lv_obj_t * parent)
{
lv_obj_t * panel = lv_obj_create(parent);
lv_obj_set_size(panel, LV_PCT(48), LV_PCT(100));
lv_obj_set_style_bg_color(panel, lv_color_hex(0x1a1a40), 0);
lv_obj_set_flex_flow(panel, LV_FLEX_FLOW_COLUMN);
lv_obj_set_style_pad_all(panel, 8, 0);
lv_obj_set_style_pad_row(panel, 4, 0);
lv_obj_remove_flag(panel, LV_OBJ_FLAG_SCROLLABLE);
/* Panel Title */
lv_obj_t * lbl = lv_label_create(panel);
lv_label_set_text(lbl, "-- OUTPUT --");
lv_obj_set_style_text_color(lbl, lv_color_hex(0xFF6600), 0);
/* LED colors and names */
lv_color_t colors[] = {
lv_palette_main(LV_PALETTE_RED),
lv_palette_main(LV_PALETTE_GREEN),
lv_palette_main(LV_PALETTE_BLUE)
};
const char * names[] = {"Red", "Green", "Blue"};
lv_event_cb_t cbs[] = {red_switch_cb, green_switch_cb, NULL};
/* Red + Green rows (Switch control) */
for (int i = 0; i < 2; i++) {
lv_obj_t * row = lv_obj_create(panel);
lv_obj_set_size(row, LV_PCT(100), 32);
lv_obj_set_flex_flow(row, LV_FLEX_FLOW_ROW);
lv_obj_set_flex_align(row, LV_FLEX_ALIGN_START,
LV_FLEX_ALIGN_CENTER,
LV_FLEX_ALIGN_CENTER);
lv_obj_set_style_bg_opa(row, LV_OPA_TRANSP, 0);
lv_obj_set_style_border_width(row, 0, 0);
lv_obj_set_style_pad_all(row, 0, 0);
lv_obj_set_style_pad_column(row, 8, 0);
lv_obj_remove_flag(row, LV_OBJ_FLAG_SCROLLABLE);
led_inds[i] = lv_led_create(row);
lv_led_set_color(led_inds[i], colors[i]);
lv_obj_set_size(led_inds[i], 20, 20);
lv_led_off(led_inds[i]);
lv_obj_t * name = lv_label_create(row);
lv_label_set_text(name, names[i]);
lv_obj_set_style_text_color(name, lv_color_hex(0xCCCCCC), 0);
led_switches[i] = lv_switch_create(row);
lv_obj_add_event_cb(led_switches[i], cbs[i],
LV_EVENT_VALUE_CHANGED, NULL);
}
/* Blue row (Slider control) */
lv_obj_t * blue_row = lv_obj_create(panel);
lv_obj_set_size(blue_row, LV_PCT(100), 32);
lv_obj_set_flex_flow(blue_row, LV_FLEX_FLOW_ROW);
lv_obj_set_flex_align(blue_row, LV_FLEX_ALIGN_START,
LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
lv_obj_set_style_bg_opa(blue_row, LV_OPA_TRANSP, 0);
lv_obj_set_style_border_width(blue_row, 0, 0);
lv_obj_set_style_pad_all(blue_row, 0, 0);
lv_obj_set_style_pad_column(blue_row, 6, 0);
lv_obj_remove_flag(blue_row, LV_OBJ_FLAG_SCROLLABLE);
led_inds[2] = lv_led_create(blue_row);
lv_led_set_color(led_inds[2], colors[2]);
lv_obj_set_size(led_inds[2], 20, 20);
lv_led_off(led_inds[2]);
blue_slider = lv_slider_create(blue_row);
lv_obj_set_width(blue_slider, 100);
lv_slider_set_range(blue_slider, 0, 100);
lv_slider_set_value(blue_slider, 0, LV_ANIM_OFF);
lv_obj_add_event_cb(blue_slider, blue_slider_cb,
LV_EVENT_VALUE_CHANGED, NULL);
blue_duty_label = lv_label_create(blue_row);
lv_label_set_text(blue_duty_label, "0%");
lv_obj_set_style_text_color(blue_duty_label,
lv_color_hex(0x00BFFF), 0);
/* Batch Buttons */
lv_obj_t * batch_row = lv_obj_create(panel);
lv_obj_set_size(batch_row, LV_PCT(100), 35);
lv_obj_set_flex_flow(batch_row, LV_FLEX_FLOW_ROW);
lv_obj_set_flex_align(batch_row, LV_FLEX_ALIGN_CENTER,
LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
lv_obj_set_style_bg_opa(batch_row, LV_OPA_TRANSP, 0);
lv_obj_set_style_border_width(batch_row, 0, 0);
lv_obj_set_style_pad_column(batch_row, 8, 0);
lv_obj_remove_flag(batch_row, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_t * btn_on = lv_button_create(batch_row);
lv_obj_set_size(btn_on, 70, 28);
lv_obj_set_style_bg_color(btn_on,
lv_palette_main(LV_PALETTE_GREEN), 0);
lv_obj_add_event_cb(btn_on, all_on_cb, LV_EVENT_CLICKED, NULL);
lv_obj_t * lo = lv_label_create(btn_on);
lv_label_set_text(lo, "All ON");
lv_obj_center(lo);
lv_obj_t * btn_off = lv_button_create(batch_row);
lv_obj_set_size(btn_off, 70, 28);
lv_obj_set_style_bg_color(btn_off,
lv_palette_main(LV_PALETTE_RED), 0);
lv_obj_add_event_cb(btn_off, all_off_cb, LV_EVENT_CLICKED, NULL);
lv_obj_t * lf = lv_label_create(btn_off);
lv_label_set_text(lf, "All OFF");
lv_obj_center(lf);
return panel;
}
/* ============================================================ */
/* MAIN FUNCTION */
/* ============================================================ */
void part1_ex9_hw_gpio_dashboard(void)
{
/* ============================== */
/* HARDWARE INITIALIZATION */
/* ============================== */
aic_gpio_init(); /* [1] GPIO */
aic_gpio_pwm_init(AIC_LED_BLUE); /* [2] PWM */
aic_sensors_init(); /* [3] ADC */
/* ============================== */
/* LVGL UI SETUP */
/* ============================== */
lv_obj_t * scr = lv_screen_active();
lv_obj_set_style_bg_color(scr, lv_color_hex(0x0a0a1a), 0);
/* --- Title --- */
lv_obj_t * title = lv_label_create(scr);
lv_label_set_text(title, "Lab 9: HW GPIO Dashboard");
lv_obj_set_style_text_color(title, lv_color_hex(0xFFFFFF), 0);
lv_obj_set_style_text_font(title, &lv_font_montserrat_16, 0);
lv_obj_align(title, LV_ALIGN_TOP_MID, 0, 5);
/* --- Main Container (2 panels side by side) --- */
lv_obj_t * main_cont = lv_obj_create(scr);
lv_obj_set_size(main_cont, 470, 195);
lv_obj_align(main_cont, LV_ALIGN_CENTER, 0, 5);
lv_obj_set_flex_flow(main_cont, LV_FLEX_FLOW_ROW);
lv_obj_set_flex_align(main_cont, LV_FLEX_ALIGN_SPACE_BETWEEN,
LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
lv_obj_set_style_bg_opa(main_cont, LV_OPA_TRANSP, 0);
lv_obj_set_style_border_width(main_cont, 0, 0);
lv_obj_set_style_pad_all(main_cont, 0, 0);
lv_obj_set_style_pad_column(main_cont, 6, 0);
lv_obj_remove_flag(main_cont, LV_OBJ_FLAG_SCROLLABLE);
/* Create Panels */
create_input_panel(main_cont);
create_output_panel(main_cont);
/* --- Status Bar --- */
status_label = lv_label_create(scr);
lv_label_set_text(status_label, "BTN=REL | ADC=0 | Blue=0%");
lv_obj_set_style_text_color(status_label, lv_color_hex(0x888888), 0);
lv_obj_align(status_label, LV_ALIGN_BOTTOM_MID, 0, -5);
/* ============================== */
/* START POLLING TIMER */
/* ============================== */
lv_timer_create(poll_timer_cb, 50, NULL);
}