#include "aic-eec.h"
#include "../aic-eec/sensors.h"
#define EX11_NUM_BUTTONS 2
/* ===== UI Elements ===== */
static lv_obj_t * ex11_btn_panels[EX11_NUM_BUTTONS];
static lv_obj_t * ex11_btn_leds[EX11_NUM_BUTTONS];
static lv_obj_t * ex11_btn_status[EX11_NUM_BUTTONS];
static lv_obj_t * ex11_slider;
static lv_obj_t * ex11_slider_value;
static lv_obj_t * ex11_output_led;
static lv_obj_t * ex11_status_label;
static lv_timer_t * ex11_poll_timer;
/* ===== Edge Detection State ===== */
static bool ex11_prev_btn0 = false;
static bool ex11_prev_btn1 = false;
static uint8_t ex11_prev_slider = 0;
/* ===== I2C Status Tracking ===== */
static uint32_t ex11_read_count = 0;
static uint32_t ex11_error_count = 0;
static bool ex11_connected = false;
/* ============================================================ */
/* HELPER: Update UI with CAPSENSE data */
/* ============================================================ */
static void ex11_update_ui(bool btn0, bool btn1,
uint8_t slider_pos, bool slider_active)
{
/* === Button 0 (CSB1) -> Red LED === */
if (btn0 != ex11_prev_btn0) {
if (btn0) {
lv_obj_set_style_bg_color(ex11_btn_panels[0],
lv_color_hex(0x00AA00), 0);
lv_led_on(ex11_btn_leds[0]);
lv_label_set_text(ex11_btn_status[0], "TOUCHED");
lv_obj_set_style_text_color(ex11_btn_status[0],
lv_color_hex(0x00FF00), 0);
aic_gpio_led_set(AIC_LED_RED, true);
} else {
lv_obj_set_style_bg_color(ex11_btn_panels[0],
lv_color_hex(0x333355), 0);
lv_led_off(ex11_btn_leds[0]);
lv_label_set_text(ex11_btn_status[0], "Ready");
lv_obj_set_style_text_color(ex11_btn_status[0],
lv_color_hex(0x888888), 0);
aic_gpio_led_set(AIC_LED_RED, false);
}
ex11_prev_btn0 = btn0;
}
/* === Button 1 (CSB2) -> Green LED === */
if (btn1 != ex11_prev_btn1) {
if (btn1) {
lv_obj_set_style_bg_color(ex11_btn_panels[1],
lv_color_hex(0x00AA00), 0);
lv_led_on(ex11_btn_leds[1]);
lv_label_set_text(ex11_btn_status[1], "TOUCHED");
lv_obj_set_style_text_color(ex11_btn_status[1],
lv_color_hex(0x00FF00), 0);
aic_gpio_led_set(AIC_LED_GREEN, true);
} else {
lv_obj_set_style_bg_color(ex11_btn_panels[1],
lv_color_hex(0x333355), 0);
lv_led_off(ex11_btn_leds[1]);
lv_label_set_text(ex11_btn_status[1], "Ready");
lv_obj_set_style_text_color(ex11_btn_status[1],
lv_color_hex(0x888888), 0);
aic_gpio_led_set(AIC_LED_GREEN, false);
}
ex11_prev_btn1 = btn1;
}
/* === Slider (CSS1) -> Blue LED PWM === */
if (slider_pos != ex11_prev_slider) {
lv_slider_set_value(ex11_slider, slider_pos, LV_ANIM_ON);
lv_label_set_text_fmt(ex11_slider_value, "%d%%", slider_pos);
uint8_t brightness = (uint8_t)((slider_pos * 255) / 100);
if (slider_active) {
lv_led_on(ex11_output_led);
lv_led_set_brightness(ex11_output_led, brightness);
} else {
lv_led_off(ex11_output_led);
}
aic_gpio_pwm_set_brightness(AIC_LED_BLUE, slider_pos);
ex11_prev_slider = slider_pos;
}
}
/* ============================================================ */
/* TIMER CALLBACK: Poll I2C every 50ms */
/* ============================================================ */
static void ex11_poll_timer_cb(lv_timer_t * timer)
{
(void)timer;
aic_capsense_data_t caps_data;
if (aic_capsense_read(&caps_data)) {
/* === I2C Read Success === */
ex11_read_count++;
if (!ex11_connected) ex11_connected = true;
/* Status: Green = OK */
lv_label_set_text_fmt(ex11_status_label,
"I2C: cnt=%u OK", (unsigned int)ex11_read_count);
lv_obj_set_style_text_color(ex11_status_label,
lv_color_hex(0x00FF00), 0);
/* Update UI with real CAPSENSE data */
ex11_update_ui(caps_data.btn0_pressed,
caps_data.btn1_pressed,
caps_data.slider_pos,
caps_data.slider_active);
} else {
/* === I2C Read Failed === */
ex11_error_count++;
if (ex11_connected) {
lv_label_set_text_fmt(ex11_status_label,
"I2C Error (err=%u)",
(unsigned int)ex11_error_count);
lv_obj_set_style_text_color(ex11_status_label,
lv_color_hex(0xFF0000), 0);
} else {
lv_label_set_text(ex11_status_label,
"I2C: No response");
lv_obj_set_style_text_color(ex11_status_label,
lv_color_hex(0xFFFF00), 0);
}
}
}
/* ============================================================ */
/* MAIN FUNCTION */
/* ============================================================ */
void part1_ex11_capsense_hardware(void)
{
/* [0] DISABLE DISPLAY TOUCH (MUST be first!) */
lv_port_indev_disable_touch();
/* [1] HARDWARE INITIALIZATION */
aic_gpio_init();
aic_gpio_pwm_init(AIC_LED_BLUE);
aic_capsense_init();
/* Reset edge detection state */
ex11_prev_btn0 = false;
ex11_prev_btn1 = false;
ex11_prev_slider = 0;
ex11_read_count = 0;
ex11_error_count = 0;
ex11_connected = false;
/* [2] LVGL UI SETUP */
lv_obj_t * scr = lv_screen_active();
lv_obj_set_style_bg_color(scr, lv_color_hex(0x1a1a2e), 0);
/* Title */
lv_obj_t * title = lv_label_create(scr);
lv_label_set_text(title, "Part 1 Ex11: CAPSENSE (I2C)");
lv_obj_set_style_text_color(title, lv_color_hex(0xFFFFFF), 0);
lv_obj_align(title, LV_ALIGN_TOP_MID, 0, 8);
/* Connection Status */
ex11_status_label = lv_label_create(scr);
if (aic_capsense_is_available()) {
lv_label_set_text(ex11_status_label, "Mode: Direct I2C (CM55)");
lv_obj_set_style_text_color(ex11_status_label,
lv_color_hex(0x00FF00), 0);
} else {
lv_label_set_text(ex11_status_label, "Mode: I2C not available");
lv_obj_set_style_text_color(ex11_status_label,
lv_color_hex(0xFFFF00), 0);
}
lv_obj_align(ex11_status_label, LV_ALIGN_TOP_MID, 0, 30);
/* ===== SLIDER PANEL (TOP) ===== */
lv_obj_t * slider_panel = lv_obj_create(scr);
lv_obj_set_size(slider_panel, 420, 80);
lv_obj_align(slider_panel, LV_ALIGN_TOP_MID, 0, 55);
lv_obj_set_style_bg_color(slider_panel, lv_color_hex(0x0f0f23), 0);
lv_obj_set_style_pad_all(slider_panel, 8, 0);
lv_obj_clear_flag(slider_panel, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_t * slider_title = lv_label_create(slider_panel);
lv_label_set_text(slider_title, "SLIDER (CSS1)");
lv_obj_set_style_text_color(slider_title, lv_color_hex(0xFFFFFF), 0);
lv_obj_align(slider_title, LV_ALIGN_TOP_LEFT, 10, 0);
ex11_slider_value = lv_label_create(slider_panel);
lv_label_set_text(ex11_slider_value, "0%");
lv_obj_set_style_text_color(ex11_slider_value, lv_color_hex(0x00AAFF), 0);
lv_obj_set_style_text_font(ex11_slider_value, &lv_font_montserrat_16, 0);
lv_obj_align(ex11_slider_value, LV_ALIGN_TOP_RIGHT, -10, 0);
ex11_slider = lv_slider_create(slider_panel);
lv_obj_set_width(ex11_slider, 340);
lv_obj_set_height(ex11_slider, 25);
lv_obj_align(ex11_slider, LV_ALIGN_BOTTOM_MID, 0, -8);
lv_slider_set_range(ex11_slider, 0, 100);
lv_obj_set_style_bg_color(ex11_slider, lv_color_hex(0x333355), LV_PART_MAIN);
lv_obj_set_style_bg_color(ex11_slider, lv_color_hex(0x00AAFF), LV_PART_INDICATOR);
lv_obj_remove_flag(ex11_slider, LV_OBJ_FLAG_CLICKABLE); /* Read-only */
ex11_output_led = lv_led_create(slider_panel);
lv_obj_set_size(ex11_output_led, 25, 25);
lv_obj_align(ex11_output_led, LV_ALIGN_BOTTOM_RIGHT, -5, -8);
lv_led_set_color(ex11_output_led, lv_palette_main(LV_PALETTE_LIGHT_BLUE));
lv_led_off(ex11_output_led);
/* ===== BUTTON PANELS (BOTTOM) ===== */
const char * btn_names[] = {"BTN0", "BTN1"};
const char * btn_ids[] = {"(CSB1)", "(CSB2)"};
uint32_t led_colors[] = {0xff0000, 0x00ff00};
int btn_x_pos[] = {-110, 110};
for (int i = 0; i < EX11_NUM_BUTTONS; i++) {
ex11_btn_panels[i] = lv_obj_create(scr);
lv_obj_set_size(ex11_btn_panels[i], 140, 150);
lv_obj_align(ex11_btn_panels[i], LV_ALIGN_BOTTOM_MID,
btn_x_pos[i], -55);
lv_obj_set_style_bg_color(ex11_btn_panels[i],
lv_color_hex(0x333355), 0);
lv_obj_set_style_border_width(ex11_btn_panels[i], 3, 0);
lv_obj_set_style_border_color(ex11_btn_panels[i],
lv_color_hex(0x666699), 0);
lv_obj_set_style_radius(ex11_btn_panels[i], 10, 0);
lv_obj_set_style_pad_all(ex11_btn_panels[i], 5, 0);
lv_obj_clear_flag(ex11_btn_panels[i], LV_OBJ_FLAG_SCROLLABLE);
lv_obj_t * name = lv_label_create(ex11_btn_panels[i]);
lv_label_set_text(name, btn_names[i]);
lv_obj_set_style_text_color(name, lv_color_hex(0xFFFFFF), 0);
lv_obj_set_style_text_font(name, &lv_font_montserrat_16, 0);
lv_obj_align(name, LV_ALIGN_TOP_MID, 0, 2);
lv_obj_t * id_lbl = lv_label_create(ex11_btn_panels[i]);
lv_label_set_text(id_lbl, btn_ids[i]);
lv_obj_set_style_text_color(id_lbl, lv_color_hex(0x888888), 0);
lv_obj_align(id_lbl, LV_ALIGN_TOP_MID, 0, 22);
ex11_btn_leds[i] = lv_led_create(ex11_btn_panels[i]);
lv_obj_set_size(ex11_btn_leds[i], 50, 50);
lv_obj_align(ex11_btn_leds[i], LV_ALIGN_CENTER, 0, 8);
lv_led_set_color(ex11_btn_leds[i], lv_color_hex(led_colors[i]));
lv_led_off(ex11_btn_leds[i]);
ex11_btn_status[i] = lv_label_create(ex11_btn_panels[i]);
lv_label_set_text(ex11_btn_status[i], "Ready");
lv_obj_set_style_text_color(ex11_btn_status[i],
lv_color_hex(0x888888), 0);
lv_obj_align(ex11_btn_status[i], LV_ALIGN_BOTTOM_MID, 0, -2);
}
/* Description + Footer */
lv_obj_t * desc = lv_label_create(scr);
lv_label_set_text(desc, "CM55 reads PSoC 4000T directly via I2C (0x08)");
lv_obj_set_style_text_color(desc, lv_color_hex(0x888888), 0);
lv_obj_align(desc, LV_ALIGN_BOTTOM_MID, 0, -25);
aic_create_footer(scr);
/* [3] START I2C POLLING (50ms = 20Hz) */
ex11_poll_timer = lv_timer_create(ex11_poll_timer_cb, 50, NULL);
}