From 7098bf4665a4057efa1c41f08b3b25dc31f0893f Mon Sep 17 00:00:00 2001 From: Ivan Li Date: Tue, 2 May 2023 14:20:37 +0800 Subject: [PATCH 1/5] feat(lvgl): base support. --- dependencies.lock | 8 +- main/CMakeLists.txt | 26 +++- main/apds_9960.c | 2 +- main/ch1116.c | 269 ++++++++++++++++++++++++++++++++++++++++ main/embedded_display.c | 145 ---------------------- main/gui.c | 171 +++++++++++++++++++++++++ main/idf_component.yml | 1 + main/lvgl_demo_ui.c | 19 +++ main/main.c | 40 +++--- main/mqtt.c | 1 - main/ui_input.c | 2 + 11 files changed, 515 insertions(+), 169 deletions(-) create mode 100644 main/ch1116.c delete mode 100644 main/embedded_display.c create mode 100644 main/gui.c create mode 100755 main/lvgl_demo_ui.c diff --git a/dependencies.lock b/dependencies.lock index 1a137fe..b09cb0b 100644 --- a/dependencies.lock +++ b/dependencies.lock @@ -10,6 +10,12 @@ dependencies: source: type: idf version: 5.0.1 -manifest_hash: d23f3b15e8b95dfe5da6cf83768d24158a3a0222f95694b1fa09c3ca8602f79f + lvgl/lvgl: + component_hash: 2567762b19953712ee38789ad8f8de57ad1f6e39283adefbbfc7184ffe662831 + source: + service_url: https://api.components.espressif.com/ + type: service + version: 8.2.0 +manifest_hash: bef1e4573234ace0f846d8355b65d9ec82a4aeada7c2fa638efbec574f134e54 target: esp32c3 version: 1.0.0 diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 2c68e4d..664b5c7 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -1,2 +1,24 @@ -idf_component_register(SRCS "udp_server.c" "service_discovery.c" "app_nvs.c" "apds_9960.c" "pca9555.c" "i2c.c" "asr_pro.c" "ci_03t.c" "ui_input.c" "ambient_light.c" "temperature.c" "embedded_display.c" "mqtt.c" "main.c" "wifi.c" "light.c" "mqtt.c" "led_strip_encoder/led_strip_encoder.c" - INCLUDE_DIRS ".") \ No newline at end of file +idf_component_register( + SRCS + "udp_server.c" + "service_discovery.c" + "app_nvs.c" + "ch1116.c" + # "apds_9960.c" + # "pca9555.c" + "i2c.c" + "asr_pro.c" + "ci_03t.c" + # "ui_input.c" + # "ambient_light.c" + # "temperature.c" + # "mqtt.c" + "main.c" + "wifi.c" + "light.c" + # "mqtt.c" + "led_strip_encoder/led_strip_encoder.c" + "gui.c" + "lvgl_demo_ui.c" + INCLUDE_DIRS "." +) \ No newline at end of file diff --git a/main/apds_9960.c b/main/apds_9960.c index 3599092..e58258d 100644 --- a/main/apds_9960.c +++ b/main/apds_9960.c @@ -1,10 +1,10 @@ #include #include +#include "ch1116.c" #include "common.h" #include "driver/gpio.h" #include "driver/i2c.h" -#include "embedded_display.c" #include "esp_log.h" #include "esp_timer.h" #include "freertos/FreeRTOS.h" diff --git a/main/ch1116.c b/main/ch1116.c new file mode 100644 index 0000000..25a225f --- /dev/null +++ b/main/ch1116.c @@ -0,0 +1,269 @@ +#pragma once + +#include + +#include "driver/gpio.h" +#include "driver/i2c.h" +#include "esp_err.h" +#include "esp_log.h" +#include "freertos/task.h" +#include "sdkconfig.h" // generated by "make menuconfig" + +#define CH1116_TAG "CH1116" + +#define SDA_PIN GPIO_NUM_4 +#define SCL_PIN GPIO_NUM_5 + +#define CH1116_WIDTH 128 +#define CH1116_HEIGHT 64 + +#define CH1116_ADDRESS 0x3C // 011110+SA0 - 0x3C or 0x3D + +// CH1116 Control + +#define CH1116_CONTROL_BYTE_COMMAND_SINGLE 0x80 +#define CH1116_CONTROL_BYTE_COMMAND_STREAM 0x00 +#define CH1116_CONTROL_BYTE_DATA_SINGLE 0xC0 +#define CH1116_CONTROL_BYTE_DATA_STREAM 0x40 + +// CH1116 Config Commands + +#define CH1116_DISPLAY_OFF 0xAE // #13 + +#define CH1116_LOWER_COLUMN_ADDRESS 0x02 // #1 0x02-0x0F +#define CH1116_HIGHER_COLUMN_ADDRESS 0x10 // #2 0x10-0x1F + +#define CH1116_DISPLAY_START_LINE 0x40 // #3 + +#define CH1116_PAGE_ADDRESS 0xB0 // #18 0xB0-0xB7 + +#define CH1116_CONTRACT_CONTROL 0x81 // #10 +#define CH1116_CONTRACT_CONTROL_128 0xCF // #10 + +#define CH1116_SEGMENT_REMAP 0xA1 // #12 ADC=1 (right) + +#define CH1116_NORMAL_DISPLAY 0xA6 // #14 + +#define CH1116_MULTIPLEX_RATIO 0xA8 // #15 +#define CH1116_MULTIPLEX_RATIO_1_64 0x3F + +// VCC Generated by Internal DC/DC Circuit +#define CH1116_CHARGE_PUMP_ENABLE 0xAD // #16 +#define CH1116_CHARGE_PUMP_ENABLE_INTERNAL_VCC 0x8B // #16 + +#define CH1116_CHARGE_PUMP_VOLTAGE_9V 0x33 // #8 + +#define CH1116_COM_SCAN_DIRECTION 0xC8 // #19 + +#define CH1116_DISPLAY_OFFSET 0xD3 // #20 +#define CH1116_DISPLAY_OFFSET_0 0x00 // #20 + +#define CH1116_SET_OSC_DIVISION 0xD5 // #21 +#define CH1116_SET_OSC_DIVISION_1 0x80 // #21 + +#define CH1116_SET_PRE_CHARGE_PERIOD 0xD9 // #22 +#define CH1116_SET_PRE_CHARGE_PERIOD_1 0x1F // #22 + +#define CH1116_SET_COM_PINS 0xDA // #23 +#define CH1116_SET_COM_PINS_1 0x12 // #23 + +#define CH1116_SET_VCOMH 0xDB // #24 +#define CH1116_SET_VCOMH_1 0x40 // #24 + +#define CH1116_DISPLAY_ON 0xAF // #13 + +void ch1116_init() { + esp_err_t err; + + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (CH1116_ADDRESS << 1) | I2C_MASTER_WRITE, true); + + i2c_master_write_byte(cmd, CH1116_CONTROL_BYTE_COMMAND_STREAM, true); + + i2c_master_write_byte(cmd, CH1116_DISPLAY_OFF, true); + + i2c_master_write_byte(cmd, CH1116_LOWER_COLUMN_ADDRESS, true); + i2c_master_write_byte(cmd, CH1116_HIGHER_COLUMN_ADDRESS, true); + + i2c_master_write_byte(cmd, CH1116_DISPLAY_START_LINE, true); + + i2c_master_write_byte(cmd, CH1116_PAGE_ADDRESS, true); + + i2c_master_write_byte(cmd, CH1116_CONTRACT_CONTROL, true); + i2c_master_write_byte(cmd, CH1116_CONTRACT_CONTROL_128, true); + + i2c_master_write_byte(cmd, CH1116_SEGMENT_REMAP, true); + + i2c_master_write_byte(cmd, CH1116_NORMAL_DISPLAY, true); + + i2c_master_write_byte(cmd, CH1116_MULTIPLEX_RATIO, true); + i2c_master_write_byte(cmd, CH1116_MULTIPLEX_RATIO_1_64, true); + + i2c_master_write_byte(cmd, CH1116_CHARGE_PUMP_ENABLE, true); + i2c_master_write_byte(cmd, CH1116_CHARGE_PUMP_ENABLE_INTERNAL_VCC, true); + + i2c_master_write_byte(cmd, CH1116_CHARGE_PUMP_VOLTAGE_9V, true); + + i2c_master_write_byte(cmd, CH1116_COM_SCAN_DIRECTION, true); + + i2c_master_write_byte(cmd, CH1116_DISPLAY_OFFSET, true); + i2c_master_write_byte(cmd, CH1116_DISPLAY_OFFSET_0, true); + + i2c_master_write_byte(cmd, CH1116_SET_OSC_DIVISION, true); + i2c_master_write_byte(cmd, CH1116_SET_OSC_DIVISION_1, true); + + i2c_master_write_byte(cmd, CH1116_SET_PRE_CHARGE_PERIOD, true); + i2c_master_write_byte(cmd, CH1116_SET_PRE_CHARGE_PERIOD_1, true); + + i2c_master_write_byte(cmd, CH1116_SET_COM_PINS, true); + i2c_master_write_byte(cmd, CH1116_SET_COM_PINS_1, true); + + i2c_master_write_byte(cmd, CH1116_SET_VCOMH, true); + i2c_master_write_byte(cmd, CH1116_SET_VCOMH_1, true); + + i2c_master_write_byte(cmd, CH1116_DISPLAY_ON, true); + + i2c_master_stop(cmd); + + err = i2c_master_cmd_begin(I2C_NUM_0, cmd, 10 / portTICK_PERIOD_MS); + if (err == ESP_OK) { + ESP_LOGI(CH1116_TAG, "OLED configured successfully"); + } else { + ESP_LOGE(CH1116_TAG, "OLED configuration failed. code: %s", + esp_err_to_name(err)); + } + i2c_cmd_link_delete(cmd); +} + +void task_ch1116_display_pattern(void *ignore) { + i2c_cmd_handle_t cmd; + + for (uint8_t i = 0; i < 8; i++) { + cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (CH1116_ADDRESS << 1) | I2C_MASTER_WRITE, true); + i2c_master_write_byte(cmd, CH1116_CONTROL_BYTE_COMMAND_SINGLE, true); + i2c_master_write_byte(cmd, 0xB0 | i, true); + i2c_master_write_byte(cmd, CH1116_CONTROL_BYTE_DATA_STREAM, true); + for (uint8_t j = 0; j < 132; j++) { + i2c_master_write_byte(cmd, 0xFF >> (j % 8), true); + } + i2c_master_stop(cmd); + i2c_master_cmd_begin(I2C_NUM_0, cmd, 10 / portTICK_PERIOD_MS); + i2c_cmd_link_delete(cmd); + } +} + +void task_ch1116_display_clear(void *ignore) { + i2c_cmd_handle_t cmd; + + uint8_t zero[132]; + memset(zero, 0, 132); + for (uint8_t i = 0; i < 8; i++) { + cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (CH1116_ADDRESS << 1) | I2C_MASTER_WRITE, true); + i2c_master_write_byte(cmd, CH1116_CONTROL_BYTE_COMMAND_SINGLE, true); + i2c_master_write_byte(cmd, 0xB0 | i, true); + + i2c_master_write_byte(cmd, CH1116_CONTROL_BYTE_DATA_STREAM, true); + i2c_master_write(cmd, zero, 132, true); + i2c_master_stop(cmd); + i2c_master_cmd_begin(I2C_NUM_0, cmd, 10 / portTICK_PERIOD_MS); + i2c_cmd_link_delete(cmd); + } + + cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, CH1116_CONTROL_BYTE_COMMAND_STREAM, true); + i2c_master_write_byte(cmd, 0x00, true); // reset column + i2c_master_write_byte(cmd, 0x10, true); + i2c_master_write_byte(cmd, 0xB0, true); // reset page + i2c_master_stop(cmd); + i2c_master_cmd_begin(I2C_NUM_0, cmd, 10 / portTICK_PERIOD_MS); + i2c_cmd_link_delete(cmd); +} + +static esp_err_t ch1116_draw_bitmap(int x_start, int y_start, int x_end, + int y_end, const void *color_data) { + assert((x_start < x_end) && (y_start < y_end) && + "start position must be smaller than end position"); + + // one page contains 8 rows (COMs) + uint8_t page_start = y_start / 8; + uint8_t page_end = y_end / 8; + // define an area of frame memory where MCU can access + + esp_err_t err; + + i2c_cmd_handle_t cmd; + + uint8_t *color_data_ptr = (uint8_t *)color_data; + uint16_t page_data_size = (x_end - x_start + 1); + + // ESP_LOGI(CH1116_TAG, "y_start: %d, y_end: %d, page_start: %d, page_end: + // %d", + // y_start, y_end, page_start, page_end); + // ESP_LOGI(CH1116_TAG, "x_start: %d, x_end: %d, page_data_size: %d", x_start, + // x_end, page_data_size); + + for (int page = page_start; page <= page_end; page++) { + cmd = i2c_cmd_link_create(); + + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (CH1116_ADDRESS << 1) | I2C_MASTER_WRITE, true); + + // set cursor position + i2c_master_write_byte(cmd, CH1116_CONTROL_BYTE_COMMAND_STREAM, true); + i2c_master_write_byte(cmd, CH1116_LOWER_COLUMN_ADDRESS | (x_start & 0x0f), + true); + i2c_master_write_byte(cmd, CH1116_HIGHER_COLUMN_ADDRESS | (x_start >> 4), + true); + i2c_master_write_byte(cmd, CH1116_PAGE_ADDRESS | (page & 0x0f), true); + + i2c_master_stop(cmd); + + err = i2c_master_cmd_begin(I2C_NUM_0, cmd, 10 / portTICK_PERIOD_MS); + if (err != ESP_OK) { + i2c_cmd_link_delete(cmd); + return err; + } + i2c_cmd_link_delete(cmd); + + // write page data + cmd = i2c_cmd_link_create(); + + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (CH1116_ADDRESS << 1) | I2C_MASTER_WRITE, true); + + i2c_master_write_byte(cmd, CH1116_CONTROL_BYTE_DATA_STREAM, true); + i2c_master_write(cmd, color_data_ptr, page_data_size, true); + + i2c_master_stop(cmd); + + err = i2c_master_cmd_begin(I2C_NUM_0, cmd, 10 / portTICK_PERIOD_MS); + + // ESP_LOG_BUFFER_HEXDUMP(CH1116_TAG, color_data_ptr, page_data_size, + // ESP_LOG_INFO); + + color_data_ptr += page_data_size; + + if (err != ESP_OK) { + i2c_cmd_link_delete(cmd); + return err; + } + i2c_cmd_link_delete(cmd); + } + + return ESP_OK; +} + +void ch1116_main(void) { + ch1116_init(); + + task_ch1116_display_pattern(NULL); + // vTaskDelay(1000 / portTICK_PERIOD_MS); + // task_ch1116_display_clear(NULL); +} \ No newline at end of file diff --git a/main/embedded_display.c b/main/embedded_display.c deleted file mode 100644 index a8f2e5e..0000000 --- a/main/embedded_display.c +++ /dev/null @@ -1,145 +0,0 @@ -#pragma once -#include -#include -#include - -#include "codetab.h" -#include "config_key.h" -#include "driver/i2c.h" -#include "esp_log.h" -#include "i2c.c" - -#define Brightness 0xCF -#define X_WIDTH 128 -#define Y_WIDTH 64 - -void i2cWriteByte(uint8_t reg, uint8_t data) { - i2c_cmd_handle_t cmd = i2c_cmd_link_create(); - i2c_master_start(cmd); - i2c_master_write_byte(cmd, SSD1306_ADDRESS << 1 | I2C_MASTER_WRITE, true); - i2c_master_write_byte(cmd, reg, true); - i2c_master_write_byte(cmd, data, true); - i2c_master_stop(cmd); - i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_PERIOD_MS); - i2c_cmd_link_delete(cmd); -} - -void i2cWriteCommand(uint8_t data) { i2cWriteByte(0x00, data); } - -void i2cWriteData(uint8_t data) { i2cWriteByte(0x40, data); } - -void display_fill(uint8_t bmpData) { - for (int y = 0; y < 8; y++) { - i2cWriteCommand(0xB0 + y); - i2cWriteCommand(0x01); - i2cWriteCommand(0x10); - for (int x = 0; x < X_WIDTH; x++) { - i2cWriteData(bmpData); - } - } -} -void display_fill_rect(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, - uint8_t bmpData) { - for (int y = y0; y < y1; y++) { - i2cWriteCommand(0xB0 + y); - i2cWriteCommand(0x01); - i2cWriteCommand(0x10); - for (int x = x0; x < x1; x++) { - i2cWriteData(bmpData); - } - } -} - -void display_set_pos(uint8_t x, uint8_t y) { - i2cWriteCommand(0xB0 + y); - i2cWriteCommand(((x & 0xF0) >> 4) | 0x10); - i2cWriteCommand((x & 0x0F) | 0x01); -} - -void display_print8_str(uint8_t x, uint8_t y, char str[]) { - if (!is_embedded_display_online) { - return; - } - uint8_t c; - for (uint8_t ch, ci = 0; ch = str[ci], ch != '\0'; ci++, x += 8) { - c = ch - 0x20; - display_set_pos(x, y); - for (uint8_t cx = 0; cx < 8; cx++) { - i2cWriteData(F8X16[c * 16 + cx]); - } - display_set_pos(x, y + 1); - for (uint8_t cx = 0; cx < 8; cx++) { - i2cWriteData(F8X16[c * 16 + cx + 8]); - }; - } -} - -void init_display() { - if (is_embedded_display_online == 0) { - ESP_LOGE("display", "display is offline"); - return; - } - - i2cWriteCommand(0xAE); // display off - i2cWriteCommand(0x00); // set lower column address - i2cWriteCommand(0x10); // set higher column address - i2cWriteCommand(0x40); // set start line address - i2cWriteCommand(0x81); // set contrast control register - i2cWriteCommand(0xCF); // set contrast - i2cWriteCommand(0xA1); // set segment re-map - i2cWriteCommand(0xC8); // set COM output scan direction - i2cWriteCommand(0xA6); // set normal display - i2cWriteCommand(0xA8); // set multiplex ratio(1 to 64) - i2cWriteCommand(0x3F); // 1/64 duty - i2cWriteCommand(0xD3); // set display offset - i2cWriteCommand(0x00); // not offset - i2cWriteCommand(0xD5); // set display clock divide ratio/oscillator frequency - i2cWriteCommand(0x80); // set divide ratio - i2cWriteCommand(0xD9); // set pre-charge period - i2cWriteCommand(0xF1); // set pre-charge voltage - i2cWriteCommand(0xDA); // set com pins hardware configuration - i2cWriteCommand(0x12); - i2cWriteCommand(0xDB); // set vcomh - i2cWriteCommand(0x40); // 0.77*vcc - i2cWriteCommand(0x20); // set memory addressing mode - i2cWriteCommand(0x02); // set page addressing mode - i2cWriteCommand(0x8D); // set charge pump enable/disable - i2cWriteCommand(0x14); // set(0x10) disable - i2cWriteCommand(0xAF); // display on - - display_fill(0x00); - display_set_pos(0, 0); -} - -void gui_update_config_uint8(uint8_t key, uint8_t value) { - char changing_str[12] = "NC"; - switch (key) { - case ui_input_key_display_0_brightness: - sprintf(changing_str, "Dis0: % 3d", value); - break; - case ui_input_key_display_1_brightness: - sprintf(changing_str, "Dis1: % 3d", value); - break; - case ui_input_key_computer_volume: - sprintf(changing_str, "CVol: % 3d", value); - break; - case ui_input_key_display_ambient_lighting_level: - sprintf(changing_str, "ALLv: % 3d", value); - break; - case ui_input_key_display_ambient_lighting_mode: - sprintf(changing_str, "ALMd: % 3d", value); - break; - case ui_input_key_display_0_mode: - sprintf(changing_str, "Dis0M: % 2d", value); - break; - case ui_input_key_display_1_mode: - sprintf(changing_str, "Dis1M: % 2d", value); - break; - - default: - strcpy(changing_str, "NC"); - break; - } - display_fill_rect(0, 6, 128, 8, 0); - display_print8_str(8, 6, changing_str); -} \ No newline at end of file diff --git a/main/gui.c b/main/gui.c new file mode 100644 index 0000000..8b8c5ea --- /dev/null +++ b/main/gui.c @@ -0,0 +1,171 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: CC0-1.0 + */ + +#include + +#include "ch1116.c" +#include "driver/i2c.h" +#include "esp_err.h" +#include "esp_log.h" +#include "esp_timer.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "lvgl.h" + +static const char *GUI_TAG = "LVGL_GUI"; + +#define I2C_HOST 0 + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////// Please update the following configuration according to your +/// LCD spec ////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#define EXAMPLE_LCD_PIXEL_CLOCK_HZ (400 * 1000) + +#define EXAMPLE_LCD_H_RES CH1116_WIDTH +#define EXAMPLE_LCD_V_RES CH1116_HEIGHT + +#define EXAMPLE_LVGL_TICK_PERIOD_MS 2 + +extern void example_lvgl_demo_ui(lv_disp_t *disp); + +static void example_lvgl_flush_cb(lv_disp_drv_t *drv, const lv_area_t *area, + lv_color_t *color_map) { + int offsetx1 = area->x1; + int offsetx2 = area->x2; + int offsety1 = area->y1; + int offsety2 = area->y2; + // copy a buffer's content to a specific area of the display + ch1116_draw_bitmap(offsetx1, offsety1, offsetx2, offsety2, color_map); + lv_disp_flush_ready(drv); +} + +static void example_lvgl_set_px_cb(lv_disp_drv_t *disp_drv, uint8_t *buf, + lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, + lv_color_t color, lv_opa_t opa) { + uint16_t byte_index = x + ((y >> 3) * buf_w); + uint8_t bit_index = y & 0x7; + + if ((color.full == 0) && (LV_OPA_TRANSP != opa)) { + buf[byte_index] |= (1 << bit_index); + } else { + buf[byte_index] &= ~(1 << bit_index); + } +} + +static void example_lvgl_rounder(lv_disp_drv_t *disp_drv, lv_area_t *area) { + area->y1 = area->y1 & (~0x7); + area->y2 = area->y2 | 0x7; +} + +static void example_increase_lvgl_tick(void *arg) { + /* Tell LVGL how many milliseconds has elapsed */ + lv_tick_inc(EXAMPLE_LVGL_TICK_PERIOD_MS); +} + +static void set_value(void *bar, int32_t v) { + lv_bar_set_value(bar, v, LV_ANIM_OFF); +} + +void lv_example_bar_6(lv_obj_t *src) { + static lv_style_t style_bar; + lv_style_init(&style_bar); + + lv_style_set_bg_color(&style_bar, lv_color_white()); + lv_style_set_border_width(&style_bar, 1); + lv_style_set_border_color(&style_bar, lv_color_black()); + lv_style_set_pad_hor(&style_bar, 4); + lv_style_set_pad_ver(&style_bar, 2); + + static lv_style_t style_indic; + lv_style_init(&style_indic); + + lv_style_set_bg_color(&style_indic, lv_color_black()); + + lv_obj_t *bar = lv_bar_create(src); + lv_obj_set_size(bar, 100, 10); + lv_obj_center(bar); + lv_obj_add_style(bar, &style_bar, LV_PART_MAIN); + lv_obj_add_style(bar, &style_indic, LV_PART_INDICATOR); + lv_bar_set_range(bar, 0, 100); + lv_bar_set_value(bar, 0, LV_ANIM_ON); + + lv_anim_t a; + lv_anim_init(&a); + lv_anim_set_exec_cb(&a, set_value); + lv_anim_set_time(&a, 3000); + lv_anim_set_playback_time(&a, 3000); + lv_anim_set_var(&a, bar); + lv_anim_set_values(&a, 0, 50); + lv_anim_set_repeat_count(&a, LV_ANIM_REPEAT_INFINITE); + lv_anim_start(&a); +} + +void example_lvgl_demo_ui(lv_disp_t *disp) { + lv_obj_t *scr = lv_disp_get_scr_act(disp); + + lv_obj_t *label = lv_label_create(scr); + lv_label_set_long_mode(label, + LV_LABEL_LONG_SCROLL_CIRCULAR); /* Circular scroll + */ + lv_label_set_text(label, "Hello Espressif, Hello LVGL."); + lv_obj_set_width(label, 120); + lv_obj_center(label); + + lv_example_bar_6(scr); +} + +static void gui_tick(void *pvParameters) { + while (1) { + // raise the task priority of LVGL and/or reduce the handler period can + // improve the performance + vTaskDelay(pdMS_TO_TICKS(10)); + // The task running lv_timer_handler should have lower priority than that + // running `lv_tick_inc` + lv_timer_handler(); + } +} +void gui_main(void) { + static lv_disp_draw_buf_t + disp_buf; // contains internal graphic buffer(s) called draw buffer(s) + static lv_disp_drv_t disp_drv; // contains callback functions + + ESP_LOGI(GUI_TAG, "Initialize LVGL library"); + lv_init(); + // alloc draw buffers used by LVGL + // it's recommended to choose the size of the draw buffer(s) to be at least + // 1/10 screen sized + lv_color_t *buf1 = malloc(EXAMPLE_LCD_H_RES * 20 * sizeof(lv_color_t)); + assert(buf1); + lv_color_t *buf2 = malloc(EXAMPLE_LCD_H_RES * 20 * sizeof(lv_color_t)); + assert(buf2); + // initialize LVGL draw buffers + lv_disp_draw_buf_init(&disp_buf, buf1, buf2, EXAMPLE_LCD_H_RES * 20); + + ESP_LOGI(GUI_TAG, "Register display driver to LVGL"); + lv_disp_drv_init(&disp_drv); + disp_drv.hor_res = EXAMPLE_LCD_H_RES; + disp_drv.ver_res = EXAMPLE_LCD_V_RES; + disp_drv.flush_cb = example_lvgl_flush_cb; + disp_drv.draw_buf = &disp_buf; + disp_drv.rounder_cb = example_lvgl_rounder; + disp_drv.set_px_cb = example_lvgl_set_px_cb; + lv_disp_t *disp = lv_disp_drv_register(&disp_drv); + + ESP_LOGI(GUI_TAG, "Install LVGL tick timer"); + // Tick interface for LVGL (using esp_timer to generate 2ms periodic event) + const esp_timer_create_args_t lvgl_tick_timer_args = { + .callback = &example_increase_lvgl_tick, .name = "lvgl_tick"}; + esp_timer_handle_t lvgl_tick_timer = NULL; + ESP_ERROR_CHECK(esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer)); + ESP_ERROR_CHECK(esp_timer_start_periodic(lvgl_tick_timer, + EXAMPLE_LVGL_TICK_PERIOD_MS * 1000)); + + ESP_LOGI(GUI_TAG, "Display LVGL Scroll Text"); + example_lvgl_demo_ui(disp); + + xTaskCreate(gui_tick, "gui_tick", 4096, (void *)NULL, 5, NULL); +} diff --git a/main/idf_component.yml b/main/idf_component.yml index a37f9a3..64f0cb2 100644 --- a/main/idf_component.yml +++ b/main/idf_component.yml @@ -1,5 +1,6 @@ ## IDF Component Manager Manifest File dependencies: + lvgl/lvgl: "~8.2.0" espressif/mdns: "^1.0.9" ## Required IDF version idf: diff --git a/main/lvgl_demo_ui.c b/main/lvgl_demo_ui.c new file mode 100755 index 0000000..28c0c69 --- /dev/null +++ b/main/lvgl_demo_ui.c @@ -0,0 +1,19 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: CC0-1.0 + */ + +#include "lvgl.h" + +void example_lvgl_demo_ui(lv_disp_t *disp) { + lv_obj_t *scr = lv_disp_get_scr_act(disp); + + lv_obj_t *label = lv_label_create(scr); + lv_label_set_long_mode(label, + LV_LABEL_LONG_SCROLL_CIRCULAR); /* Circular scroll + */ + lv_label_set_text(label, "Hello Espressif, Hello LVGL."); + lv_obj_set_width(label, 120); + lv_obj_align(label, LV_ALIGN_TOP_MID, 0, 0); +} diff --git a/main/main.c b/main/main.c index b8f81d9..d12c9dd 100644 --- a/main/main.c +++ b/main/main.c @@ -1,19 +1,20 @@ -#include "apds_9960.c" +// #include "apds_9960.c" #include "app_nvs.c" +#include "ch1116.c" #include "ci_03t.c" -#include "embedded_display.c" #include "esp_log.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" +#include "gui.c" #include "i2c.c" #include "light.c" -#include "mqtt.c" -#include "pca9555.c" +// #include "mqtt.c" +// #include "pca9555.c" #include "sdkconfig.h" #include "service_discovery.c" -#include "temperature.c" +// #include "temperature.c" #include "udp_server.c" -#include "ui_input.c" +// #include "ui_input.c" #include "wifi.c" static const char *APP_TAG = "DisplayAmbientLight"; @@ -26,17 +27,18 @@ void app_main(void) { init_i2c(); i2c_check_slaves(); - init_display(); - display_print8_str(0, 0, "Ambient Light"); + ch1116_main(); + gui_main(); + // display_print8_str(0, 0, "Ambient Light"); ci_03t_init(); - apds_9960_init(); - apds_9960_auto_fetch(); - auto_fetch_temperature(); - pca9555_init(); - ui_input_init(); - xTaskCreate(mqtt_publish_ui_input, "mqtt_publish_ui_input", 2048, NULL, 10, - NULL); + // apds_9960_init(); + // apds_9960_auto_fetch(); + // auto_fetch_temperature(); + // pca9555_init(); + // ui_input_init(); + // xTaskCreate(mqtt_publish_ui_input, "mqtt_publish_ui_input", 2048, NULL, 10, + // NULL); vTaskDelay(pdMS_TO_TICKS(10)); light_play(light_mode_connection_wifi); if (connect_wifi()) { @@ -45,14 +47,14 @@ void app_main(void) { udp_server_init(); service_discovery_init(); vTaskDelay(pdMS_TO_TICKS(1000)); - mqtt_app_start(); + // mqtt_app_start(); // if (waiting_for_mqtt_connected()) { // light_play(light_mode_mqtt_connected); // } // if (waiting_for_desktop_online()) { // light_play(light_mode_desktop_online); // } - while (waiting_and_get_colors()) { - light_play_colors(NUMBER_OF_LEDS * 3, mqtt_colors_buffer); - } + // while (waiting_and_get_colors()) { + // light_play_colors(NUMBER_OF_LEDS * 3, mqtt_colors_buffer); + // } } diff --git a/main/mqtt.c b/main/mqtt.c index f092e75..fde480d 100644 --- a/main/mqtt.c +++ b/main/mqtt.c @@ -4,7 +4,6 @@ #include "cJSON.h" #include "ci_03t.c" -#include "embedded_display.c" #include "esp_bit_defs.h" #include "esp_event.h" #include "esp_log.h" diff --git a/main/ui_input.c b/main/ui_input.c index 64af189..425c6da 100644 --- a/main/ui_input.c +++ b/main/ui_input.c @@ -148,6 +148,8 @@ static void encoder_value_change(encoder_state_t *state) { return; } + ESP_LOGI(UI_INPUT_TAG, "key: %d, delta: %d", state->key, delta); + s_ui_input_t event = {.value = delta}; if (state->key == ui_input_raw_key_encoder_0) { if (state->value & 1) { From b7476428a2476c8986342e2746f0fdfef1e1ef6a Mon Sep 17 00:00:00 2001 From: Ivan Li Date: Tue, 2 May 2023 20:06:30 +0800 Subject: [PATCH 2/5] =?UTF-8?q?feat:=20=E8=81=94=E7=BD=91=E7=8A=B6?= =?UTF-8?q?=E6=80=81=E6=8C=87=E7=A4=BA=E5=9B=BE=E6=A0=87=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dependencies.lock | 6 +- main/CMakeLists.txt | 1 + main/app_icon_8.c | 157 +++++++++++++++++++++++++++++++++++++++++ main/gui.c | 146 ++++++++++++++++++++++++++++++++++++-- main/idf_component.yml | 2 +- main/main.c | 17 +++-- main/wifi.c | 9 +-- 7 files changed, 316 insertions(+), 22 deletions(-) create mode 100644 main/app_icon_8.c diff --git a/dependencies.lock b/dependencies.lock index b09cb0b..8130993 100644 --- a/dependencies.lock +++ b/dependencies.lock @@ -11,11 +11,11 @@ dependencies: type: idf version: 5.0.1 lvgl/lvgl: - component_hash: 2567762b19953712ee38789ad8f8de57ad1f6e39283adefbbfc7184ffe662831 + component_hash: 0f2006e7b800eee17b73ed4f92ffbaa76d61c02ba4779ec9efbcd5f453bb0102 source: service_url: https://api.components.espressif.com/ type: service - version: 8.2.0 -manifest_hash: bef1e4573234ace0f846d8355b65d9ec82a4aeada7c2fa638efbec574f134e54 + version: 8.3.6~1 +manifest_hash: 9a88337b9db92c26041847f5fd4efc58df1dcf0e9c6b8758da96aaac2e63c2a2 target: esp32c3 version: 1.0.0 diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 664b5c7..04d7f5c 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -20,5 +20,6 @@ idf_component_register( "led_strip_encoder/led_strip_encoder.c" "gui.c" "lvgl_demo_ui.c" + "app_icon_8.c" INCLUDE_DIRS "." ) \ No newline at end of file diff --git a/main/app_icon_8.c b/main/app_icon_8.c new file mode 100644 index 0000000..b9efeb2 --- /dev/null +++ b/main/app_icon_8.c @@ -0,0 +1,157 @@ +/******************************************************************************* + * Size: 8 px + * Bpp: 1 + * Opts: + ******************************************************************************/ +#pragma once + +#include "lvgl.h" + +#ifndef APP_ICON_8 +#define APP_ICON_8 1 +#endif + +#if APP_ICON_8 + +/*----------------- + * BITMAPS + *----------------*/ + +/*Store the image of the glyphs*/ +static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { + /* U+E1CB "" */ + 0x38, 0x31, 0x88, 0xfa, 0x49, 0x54, 0x44, 0x10, 0xf8, + + /* U+E1CC "" */ + 0x80, 0x1f, 0xa, 0x22, 0x6b, 0xd4, 0x44, 0xd0, 0xc8, 0x1, + + /* U+E29E "" */ + 0xe, 0x4, 0xa8, 0x32, 0x18, 0xe, 0xd, 0x8c, 0x7c, + + /* U+F1EB "" */ + 0x1e, 0x18, 0x68, 0x4, 0x78, 0x21, 0x0, 0x0, 0xc0, 0x0, + + /* U+F6AA "" */ + 0xc0, + + /* U+F6AB "" */ + 0x79, 0x8, 0x1, 0x80}; + +/*--------------------- + * GLYPH DESCRIPTION + *--------------------*/ + +static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = { + {.bitmap_index = 0, + .adv_w = 0, + .box_w = 0, + .box_h = 0, + .ofs_x = 0, + .ofs_y = 0} /* id = 0 reserved */, + {.bitmap_index = 0, + .adv_w = 160, + .box_w = 10, + .box_h = 7, + .ofs_x = 0, + .ofs_y = 0}, + {.bitmap_index = 9, + .adv_w = 160, + .box_w = 10, + .box_h = 8, + .ofs_x = 0, + .ofs_y = -1}, + {.bitmap_index = 19, + .adv_w = 128, + .box_w = 9, + .box_h = 8, + .ofs_x = 0, + .ofs_y = -1}, + {.bitmap_index = 28, + .adv_w = 160, + .box_w = 10, + .box_h = 8, + .ofs_x = 0, + .ofs_y = -1}, + {.bitmap_index = 38, + .adv_w = 32, + .box_w = 2, + .box_h = 2, + .ofs_x = 4, + .ofs_y = -1}, + {.bitmap_index = 39, + .adv_w = 112, + .box_w = 7, + .box_h = 4, + .ofs_x = 2, + .ofs_y = 0}}; + +/*--------------------- + * CHARACTER MAPPING + *--------------------*/ + +static const uint16_t unicode_list_0[] = {0x0, 0x1, 0xd3, + 0x1020, 0x14df, 0x14e0}; + +/*Collect the unicode lists and glyph_id offsets*/ +static const lv_font_fmt_txt_cmap_t cmaps[] = { + {.range_start = 57803, + .range_length = 5345, + .glyph_id_start = 1, + .unicode_list = unicode_list_0, + .glyph_id_ofs_list = NULL, + .list_length = 6, + .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY}}; + +/*-------------------- + * ALL CUSTOM DATA + *--------------------*/ + +#if LV_VERSION_CHECK(8, 0, 0) +/*Store all the custom data of the font*/ +static lv_font_fmt_txt_glyph_cache_t cache; +static const lv_font_fmt_txt_dsc_t font_dsc = { +#else +static lv_font_fmt_txt_dsc_t font_dsc = { +#endif + .glyph_bitmap = glyph_bitmap, + .glyph_dsc = glyph_dsc, + .cmaps = cmaps, + .kern_dsc = NULL, + .kern_scale = 0, + .cmap_num = 1, + .bpp = 1, + .kern_classes = 0, + .bitmap_format = 0, +#if LV_VERSION_CHECK(8, 0, 0) + .cache = &cache +#endif +}; + +/*----------------- + * PUBLIC FONT + *----------------*/ + +/*Initialize a public general font descriptor*/ +#if LV_VERSION_CHECK(8, 0, 0) +const lv_font_t app_icon_8 = { +#else +lv_font_t app_icon_8 = { +#endif + .get_glyph_dsc = + lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/ + .get_glyph_bitmap = + lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/ + .line_height = 8, /*The maximum line height required by the font*/ + .base_line = 1, /*Baseline measured from the bottom of the line*/ +#if !(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0) + .subpx = LV_FONT_SUBPX_NONE, +#endif +#if LV_VERSION_CHECK(7, 4, 0) || LVGL_VERSION_MAJOR >= 8 + .underline_position = -1, + .underline_thickness = 0, +#endif + .dsc = &font_dsc /*The custom font data. Will be accessed by + `get_glyph_bitmap/dsc` */ +}; + +#endif /*#if APP_ICON_8*/ diff --git a/main/gui.c b/main/gui.c index 8b8c5ea..f7194fe 100644 --- a/main/gui.c +++ b/main/gui.c @@ -6,6 +6,7 @@ #include +#include "app_icon_8.c" #include "ch1116.c" #include "driver/i2c.h" #include "esp_err.h" @@ -19,10 +20,6 @@ static const char *GUI_TAG = "LVGL_GUI"; #define I2C_HOST 0 -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -//////////////////// Please update the following configuration according to your -/// LCD spec ////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #define EXAMPLE_LCD_PIXEL_CLOCK_HZ (400 * 1000) #define EXAMPLE_LCD_H_RES CH1116_WIDTH @@ -30,6 +27,21 @@ static const char *GUI_TAG = "LVGL_GUI"; #define EXAMPLE_LVGL_TICK_PERIOD_MS 2 +// EF 9A AA +#define APP_WIFI_WEAK_SYMBOL "\xEF\x9A\xAA" +// EF 9A AB +#define APP_WIFI_FAIR_SYMBOL "\xEF\x9A\xAB" +// EF 87 AB +#define APP_WIFI_GOOD_SYMBOL "\xEF\x87\xAB" + +// EE 87 8C +#define APP_CONNECTED_SYMBOL "\xEE\x87\x8C" +// EE 87 8B +#define APP_DISCONNECTED_SYMBOL "\xEE\x87\x8B" + +// EE 8A 9E +#define APP_TIMER_SYMBOL "\xEE\x8A\x9E" + extern void example_lvgl_demo_ui(lv_disp_t *disp); static void example_lvgl_flush_cb(lv_disp_drv_t *drv, const lv_area_t *area, @@ -56,6 +68,15 @@ static void example_lvgl_set_px_cb(lv_disp_drv_t *disp_drv, uint8_t *buf, } } +static lv_obj_t *wifi_label; +static lv_anim_t wifi_animate; + +static lv_obj_t *timer_label; +static lv_anim_t timer_animate; + +static lv_obj_t *desktop_label; +static lv_anim_t desktop_animate; + static void example_lvgl_rounder(lv_disp_drv_t *disp_drv, lv_area_t *area) { area->y1 = area->y1 & (~0x7); area->y2 = area->y2 | 0x7; @@ -70,6 +91,86 @@ static void set_value(void *bar, int32_t v) { lv_bar_set_value(bar, v, LV_ANIM_OFF); } +static void set_visible(void *obj, int32_t v) { + if (v) { + lv_obj_clear_flag(obj, LV_OBJ_FLAG_HIDDEN); + } else { + lv_obj_add_flag(obj, LV_OBJ_FLAG_HIDDEN); + } +} + +static void set_obj_blink_animate(lv_obj_t *obj, lv_anim_t *a) { + lv_anim_init(a); + lv_anim_set_exec_cb(a, set_visible); + lv_anim_set_time(a, 100); + lv_anim_set_playback_time(a, 100); + lv_anim_set_playback_delay(a, 200); + lv_anim_set_repeat_delay(a, 200); + lv_anim_set_values(a, 0, 1); + lv_anim_set_var(a, obj); + lv_anim_set_repeat_count(a, LV_ANIM_REPEAT_INFINITE); + lv_anim_start(a); +} + +static void change_wifi_icon(void *obj, int32_t v) { + switch (v) { + case 0: + lv_label_set_text(obj, APP_WIFI_WEAK_SYMBOL); + break; + case 1: + lv_label_set_text(obj, APP_WIFI_FAIR_SYMBOL); + break; + case 2: + lv_label_set_text(obj, APP_WIFI_GOOD_SYMBOL); + break; + default: + ESP_LOGW(GUI_TAG, "Unknown wifi strength: %ld", v); + break; + } +} + +static void gui_set_wifi_connecting() { + lv_obj_clear_flag(wifi_label, LV_OBJ_FLAG_HIDDEN); + + lv_anim_init(&wifi_animate); + lv_anim_set_exec_cb(&wifi_animate, change_wifi_icon); + lv_anim_set_time(&wifi_animate, 300); + lv_anim_set_repeat_delay(&wifi_animate, 300); + lv_anim_set_values(&wifi_animate, 0, 2); + lv_anim_set_var(&wifi_animate, wifi_label); + lv_anim_set_repeat_count(&wifi_animate, LV_ANIM_REPEAT_INFINITE); + lv_anim_start(&wifi_animate); +} + +static void gui_set_wifi_connected() { + lv_anim_del(wifi_label, NULL); + + lv_obj_clear_flag(wifi_label, LV_OBJ_FLAG_HIDDEN); + lv_label_set_text(wifi_label, APP_WIFI_GOOD_SYMBOL); +} + +static void gui_set_wifi_disconnected() { + lv_anim_del(&wifi_label, NULL); + lv_obj_clear_flag(wifi_label, LV_OBJ_FLAG_HIDDEN); + lv_label_set_text(wifi_label, APP_WIFI_WEAK_SYMBOL); +} + +static void gui_set_server_connecting() { + set_obj_blink_animate(desktop_label, &desktop_animate); +} + +static void gui_set_server_connected() { + lv_anim_del(&desktop_label, NULL); + lv_obj_clear_flag(desktop_label, LV_OBJ_FLAG_HIDDEN); + lv_label_set_text(desktop_label, APP_CONNECTED_SYMBOL); +} + +static void gui_set_server_disconnected() { + lv_anim_del(&desktop_label, NULL); + lv_obj_clear_flag(desktop_label, LV_OBJ_FLAG_HIDDEN); + lv_label_set_text(desktop_label, APP_DISCONNECTED_SYMBOL); +} + void lv_example_bar_6(lv_obj_t *src) { static lv_style_t style_bar; lv_style_init(&style_bar); @@ -104,6 +205,38 @@ void lv_example_bar_6(lv_obj_t *src) { lv_anim_start(&a); } +void gui_status_bar_create(lv_obj_t *scr) { + // wifi icon + wifi_label = lv_label_create(scr); + lv_label_set_long_mode(wifi_label, LV_LABEL_LONG_SCROLL_CIRCULAR); + lv_label_set_text(wifi_label, APP_WIFI_GOOD_SYMBOL); + lv_obj_set_width(wifi_label, 10); + lv_obj_align(wifi_label, LV_ALIGN_OUT_TOP_LEFT, 0, 0); + lv_obj_set_style_text_color(wifi_label, lv_color_black(), LV_PART_MAIN); + lv_obj_set_style_text_font(wifi_label, &app_icon_8, LV_PART_MAIN); + lv_obj_add_flag(wifi_label, LV_OBJ_FLAG_HIDDEN); + + // timer icon + timer_label = lv_label_create(scr); + lv_label_set_long_mode(timer_label, LV_LABEL_LONG_SCROLL_CIRCULAR); + lv_label_set_text(timer_label, APP_TIMER_SYMBOL); + lv_obj_set_width(timer_label, 10); + lv_obj_align(timer_label, LV_ALIGN_OUT_TOP_LEFT, 12, 0); + lv_obj_set_style_text_color(timer_label, lv_color_black(), LV_PART_MAIN); + lv_obj_set_style_text_font(timer_label, &app_icon_8, LV_PART_MAIN); + lv_obj_add_flag(timer_label, LV_OBJ_FLAG_HIDDEN); + + // desktop icon + desktop_label = lv_label_create(scr); + lv_label_set_long_mode(desktop_label, LV_LABEL_LONG_SCROLL_CIRCULAR); + lv_label_set_text(desktop_label, APP_CONNECTED_SYMBOL); + lv_obj_set_width(desktop_label, 10); + lv_obj_align(desktop_label, LV_ALIGN_OUT_TOP_LEFT, 24, 0); + lv_obj_set_style_text_color(desktop_label, lv_color_black(), LV_PART_MAIN); + lv_obj_set_style_text_font(desktop_label, &app_icon_8, LV_PART_MAIN); + lv_obj_add_flag(desktop_label, LV_OBJ_FLAG_HIDDEN); +} + void example_lvgl_demo_ui(lv_disp_t *disp) { lv_obj_t *scr = lv_disp_get_scr_act(disp); @@ -113,9 +246,11 @@ void example_lvgl_demo_ui(lv_disp_t *disp) { */ lv_label_set_text(label, "Hello Espressif, Hello LVGL."); lv_obj_set_width(label, 120); - lv_obj_center(label); + lv_obj_align(label, LV_ALIGN_BOTTOM_RIGHT, 0, 0); lv_example_bar_6(scr); + + gui_status_bar_create(scr); } static void gui_tick(void *pvParameters) { @@ -128,6 +263,7 @@ static void gui_tick(void *pvParameters) { lv_timer_handler(); } } + void gui_main(void) { static lv_disp_draw_buf_t disp_buf; // contains internal graphic buffer(s) called draw buffer(s) diff --git a/main/idf_component.yml b/main/idf_component.yml index 64f0cb2..8e84cca 100644 --- a/main/idf_component.yml +++ b/main/idf_component.yml @@ -1,6 +1,6 @@ ## IDF Component Manager Manifest File dependencies: - lvgl/lvgl: "~8.2.0" + lvgl/lvgl: "^8.3.6~1" espressif/mdns: "^1.0.9" ## Required IDF version idf: diff --git a/main/main.c b/main/main.c index d12c9dd..b45a2ed 100644 --- a/main/main.c +++ b/main/main.c @@ -23,15 +23,19 @@ void app_main(void) { app_nvs_init(); light_init_strip(); - gpio_install_isr_service(0); + // gpio_install_isr_service(0); init_i2c(); i2c_check_slaves(); ch1116_main(); gui_main(); + + gui_set_wifi_connecting(); + gui_set_server_connecting(); + // display_print8_str(0, 0, "Ambient Light"); - ci_03t_init(); + // ci_03t_init(); // apds_9960_init(); // apds_9960_auto_fetch(); // auto_fetch_temperature(); @@ -39,14 +43,17 @@ void app_main(void) { // ui_input_init(); // xTaskCreate(mqtt_publish_ui_input, "mqtt_publish_ui_input", 2048, NULL, 10, // NULL); - vTaskDelay(pdMS_TO_TICKS(10)); + // vTaskDelay(pdMS_TO_TICKS(10)); light_play(light_mode_connection_wifi); if (connect_wifi()) { + gui_set_wifi_connected(); light_play(light_mode_idle); + } else { + gui_set_wifi_disconnected(); } udp_server_init(); - service_discovery_init(); - vTaskDelay(pdMS_TO_TICKS(1000)); + // service_discovery_init(); + // vTaskDelay(pdMS_TO_TICKS(1000)); // mqtt_app_start(); // if (waiting_for_mqtt_connected()) { // light_play(light_mode_mqtt_connected); diff --git a/main/wifi.c b/main/wifi.c index eae3a83..94f1a80 100644 --- a/main/wifi.c +++ b/main/wifi.c @@ -151,14 +151,7 @@ bool wifi_init_sta(void) { } bool connect_wifi(void) { - // Initialize NVS - esp_err_t ret = nvs_flash_init(); - if (ret == ESP_ERR_NVS_NO_FREE_PAGES || - ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { - ESP_ERROR_CHECK(nvs_flash_erase()); - ret = nvs_flash_init(); - } - ESP_ERROR_CHECK(ret); + //! Should init NVS before wifi init ESP_LOGI(WIFI_TAG, "ESP_WIFI_MODE_STA"); return wifi_init_sta(); From 324a307fe34771c3d0d5260380138aba4de4dbac Mon Sep 17 00:00:00 2001 From: Ivan Li Date: Wed, 3 May 2023 00:05:04 +0800 Subject: [PATCH 3/5] feat: desktop connection status icon. --- main/gui.c | 21 ++++++++++----------- main/main.c | 2 +- main/udp_server.c | 29 +++++++++++++++++++++++++++-- 3 files changed, 38 insertions(+), 14 deletions(-) diff --git a/main/gui.c b/main/gui.c index f7194fe..5144cef 100644 --- a/main/gui.c +++ b/main/gui.c @@ -1,8 +1,4 @@ -/* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: CC0-1.0 - */ +#pragma once #include @@ -34,10 +30,10 @@ static const char *GUI_TAG = "LVGL_GUI"; // EF 87 AB #define APP_WIFI_GOOD_SYMBOL "\xEF\x87\xAB" -// EE 87 8C -#define APP_CONNECTED_SYMBOL "\xEE\x87\x8C" // EE 87 8B -#define APP_DISCONNECTED_SYMBOL "\xEE\x87\x8B" +#define APP_CONNECTED_SYMBOL "\xEE\x87\x8B" +// EE 87 8C +#define APP_DISCONNECTED_SYMBOL "\xEE\x87\x8C" // EE 8A 9E #define APP_TIMER_SYMBOL "\xEE\x8A\x9E" @@ -144,13 +140,14 @@ static void gui_set_wifi_connecting() { static void gui_set_wifi_connected() { lv_anim_del(wifi_label, NULL); - + vTaskDelay(300 / portTICK_PERIOD_MS); lv_obj_clear_flag(wifi_label, LV_OBJ_FLAG_HIDDEN); lv_label_set_text(wifi_label, APP_WIFI_GOOD_SYMBOL); } static void gui_set_wifi_disconnected() { lv_anim_del(&wifi_label, NULL); + vTaskDelay(300 / portTICK_PERIOD_MS); lv_obj_clear_flag(wifi_label, LV_OBJ_FLAG_HIDDEN); lv_label_set_text(wifi_label, APP_WIFI_WEAK_SYMBOL); } @@ -160,13 +157,15 @@ static void gui_set_server_connecting() { } static void gui_set_server_connected() { - lv_anim_del(&desktop_label, NULL); + lv_anim_del(desktop_label, NULL); + vTaskDelay(300 / portTICK_PERIOD_MS); lv_obj_clear_flag(desktop_label, LV_OBJ_FLAG_HIDDEN); lv_label_set_text(desktop_label, APP_CONNECTED_SYMBOL); } static void gui_set_server_disconnected() { - lv_anim_del(&desktop_label, NULL); + lv_anim_del(desktop_label, NULL); + vTaskDelay(300 / portTICK_PERIOD_MS); lv_obj_clear_flag(desktop_label, LV_OBJ_FLAG_HIDDEN); lv_label_set_text(desktop_label, APP_DISCONNECTED_SYMBOL); } diff --git a/main/main.c b/main/main.c index b45a2ed..bb7812e 100644 --- a/main/main.c +++ b/main/main.c @@ -52,7 +52,7 @@ void app_main(void) { gui_set_wifi_disconnected(); } udp_server_init(); - // service_discovery_init(); + service_discovery_init(); // vTaskDelay(pdMS_TO_TICKS(1000)); // mqtt_app_start(); // if (waiting_for_mqtt_connected()) { diff --git a/main/udp_server.c b/main/udp_server.c index 485acbb..e752070 100644 --- a/main/udp_server.c +++ b/main/udp_server.c @@ -10,6 +10,7 @@ #include "esp_wifi.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" +#include "gui.c" #include "light.c" #include "lwip/err.h" #include "lwip/sockets.h" @@ -20,6 +21,9 @@ static const char *UDP_SERVER_TAG = "UDP_SERVER"; +static bool desktop_connected = false; +static uint64_t last_desktop_ping_at = 0; + static void udp_server_task(void *pvParameters) { char rx_buffer[1024]; char addr_str[128]; @@ -84,6 +88,7 @@ static void udp_server_task(void *pvParameters) { switch (rx_buffer[0]) { case 1: + last_desktop_ping_at = esp_timer_get_time(); sendto(sock, rx_buffer, 1, 0, (struct sockaddr *)&source_addr, sizeof(source_addr)); break; @@ -127,8 +132,28 @@ static void udp_server_task(void *pvParameters) { vTaskDelete(NULL); } +static void change_desktop_connection_status(bool connected) { + desktop_connected = connected; + if (connected) { + gui_set_server_connected(); + } else { + gui_set_server_disconnected(); + } +} + +static void desktop_online_check_task(void *pvParameters) { + while (1) { + if (esp_timer_get_time() - last_desktop_ping_at > 5000000) { // 2 seconds + change_desktop_connection_status(false); + } else { + change_desktop_connection_status(true); + } + vTaskDelay(1000 / portTICK_PERIOD_MS); + } +} + void udp_server_init(void) { - ESP_ERROR_CHECK(nvs_flash_init()); - ESP_ERROR_CHECK(esp_netif_init()); xTaskCreate(udp_server_task, "udp_server", 4096, (void *)AF_INET, 5, NULL); + xTaskCreate(desktop_online_check_task, "desktop_online_check", 4096, NULL, 10, + NULL); } \ No newline at end of file From 27270c4f6a8dc707ffc040ea505bcbc46706a71e Mon Sep 17 00:00:00 2001 From: Ivan Li Date: Wed, 3 May 2023 18:10:21 +0800 Subject: [PATCH 4/5] =?UTF-8?q?feat(gui):=20=E7=81=AF=E6=9D=A1=E4=BA=AE?= =?UTF-8?q?=E5=BA=A6=E8=B0=83=E6=95=B4=E7=95=8C=E9=9D=A2=E3=80=82=20close?= =?UTF-8?q?=20#6.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main/CMakeLists.txt | 5 +-- main/gui.c | 97 ++++++++++++++++++++++++++++++++++++++++++++- main/main.c | 8 ++-- main/pca9555.c | 5 --- main/ui_input.c | 6 +-- 5 files changed, 104 insertions(+), 17 deletions(-) diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 04d7f5c..410cd0a 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -5,18 +5,17 @@ idf_component_register( "app_nvs.c" "ch1116.c" # "apds_9960.c" - # "pca9555.c" + "pca9555.c" "i2c.c" "asr_pro.c" "ci_03t.c" - # "ui_input.c" + "ui_input.c" # "ambient_light.c" # "temperature.c" # "mqtt.c" "main.c" "wifi.c" "light.c" - # "mqtt.c" "led_strip_encoder/led_strip_encoder.c" "gui.c" "lvgl_demo_ui.c" diff --git a/main/gui.c b/main/gui.c index 5144cef..4fe4ee1 100644 --- a/main/gui.c +++ b/main/gui.c @@ -73,6 +73,13 @@ static lv_anim_t timer_animate; static lv_obj_t *desktop_label; static lv_anim_t desktop_animate; +static lv_obj_t *value_setting_panel; +static lv_obj_t *value_setting_bar; +static lv_obj_t *value_setting_label; +static lv_obj_t *value_setting_value_label; + +static lv_obj_t *scr; + static void example_lvgl_rounder(lv_disp_drv_t *disp_drv, lv_area_t *area) { area->y1 = area->y1 & (~0x7); area->y2 = area->y2 | 0x7; @@ -170,6 +177,92 @@ static void gui_set_server_disconnected() { lv_label_set_text(desktop_label, APP_DISCONNECTED_SYMBOL); } +static void gui_bar_value_update_cb(lv_event_t *e) { + lv_obj_draw_part_dsc_t *dsc = lv_event_get_param(e); + if (dsc->part != LV_PART_INDICATOR) return; + + lv_obj_t *obj = lv_event_get_target(e); + + lv_draw_label_dsc_t label_dsc; + lv_draw_label_dsc_init(&label_dsc); + label_dsc.font = &lv_font_montserrat_8; + + char buf[8]; + lv_snprintf(buf, sizeof(buf), "%ld", lv_bar_get_value(obj)); + + lv_point_t txt_size; + lv_txt_get_size(&txt_size, buf, label_dsc.font, label_dsc.letter_space, + label_dsc.line_space, LV_COORD_MAX, label_dsc.flag); + + lv_coord_t txt_x; + /*If the indicator is long enough put the text inside on the right*/ + if (lv_area_get_width(dsc->draw_area) > txt_size.x + 20) { + txt_x = dsc->draw_area->x2 - 8 - txt_size.x + 1; + lv_obj_set_style_text_color(value_setting_value_label, lv_color_white(), + LV_PART_MAIN); + label_dsc.color = lv_color_white(); + } + /*If the indicator is still short put the text out of it on the right*/ + else { + txt_x = dsc->draw_area->x2 - 8 + txt_size.x - 1; + lv_obj_set_style_text_color(value_setting_value_label, lv_color_black(), + LV_PART_MAIN); + } + + ESP_LOGI(GUI_TAG, "value_setting_value_label: %s", buf); + + lv_obj_align(value_setting_value_label, LV_ALIGN_LEFT_MID, txt_x, 0); + lv_label_set_text(value_setting_value_label, buf); + lv_obj_set_width(value_setting_value_label, txt_size.x); +} + +static void gui_create_value_setting_panel() { + if (value_setting_panel != NULL) { + return; + } + + value_setting_panel = lv_obj_create(scr); + lv_obj_set_size(value_setting_panel, 128, 40); + lv_obj_align(value_setting_panel, LV_ALIGN_BOTTOM_MID, 0, 0); + lv_obj_set_style_border_width(value_setting_panel, 1, LV_PART_MAIN); + lv_obj_set_style_border_color(value_setting_panel, lv_color_black(), + LV_PART_MAIN); + lv_obj_set_style_radius(value_setting_panel, 5, LV_PART_MAIN); + lv_obj_set_style_pad_all(value_setting_panel, 2, LV_PART_MAIN); + + value_setting_label = lv_label_create(value_setting_panel); + lv_obj_align(value_setting_label, LV_ALIGN_BOTTOM_LEFT, 0, 0); + + value_setting_bar = lv_bar_create(value_setting_panel); + lv_obj_set_size(value_setting_bar, 120, 12); + lv_obj_align(value_setting_bar, LV_ALIGN_TOP_MID, 0, 0); + lv_bar_set_range(value_setting_bar, 0, 100); + lv_bar_set_value(value_setting_bar, 50, LV_ANIM_ON); + lv_obj_set_style_bg_color(value_setting_bar, lv_color_white(), LV_PART_MAIN); + lv_obj_set_style_border_color(value_setting_bar, lv_color_black(), + LV_PART_MAIN); + lv_obj_set_style_border_width(value_setting_bar, 1, LV_PART_MAIN); + lv_obj_set_style_radius(value_setting_bar, 5, LV_PART_MAIN); + lv_obj_set_style_pad_hor(value_setting_bar, 0, LV_PART_MAIN); + lv_obj_set_style_pad_ver(value_setting_bar, 2, LV_PART_MAIN); + lv_obj_set_style_bg_color(value_setting_bar, lv_color_black(), + LV_PART_INDICATOR); + lv_obj_add_event_cb(value_setting_bar, gui_bar_value_update_cb, + LV_EVENT_DRAW_PART_END, NULL); + + value_setting_value_label = lv_label_create(value_setting_bar); + lv_obj_align(value_setting_value_label, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_style_text_font(value_setting_value_label, &lv_font_montserrat_8, + LV_PART_MAIN); +} + +static void gui_change_strip_level(int32_t target_value) { + gui_create_value_setting_panel(); + lv_label_set_text(value_setting_label, "Strip Level"); + lv_bar_set_range(value_setting_bar, 0, 255); + lv_bar_set_value(value_setting_bar, target_value, LV_ANIM_ON); +} + void lv_example_bar_6(lv_obj_t *src) { static lv_style_t style_bar; lv_style_init(&style_bar); @@ -237,7 +330,7 @@ void gui_status_bar_create(lv_obj_t *scr) { } void example_lvgl_demo_ui(lv_disp_t *disp) { - lv_obj_t *scr = lv_disp_get_scr_act(disp); + scr = lv_disp_get_scr_act(disp); lv_obj_t *label = lv_label_create(scr); lv_label_set_long_mode(label, @@ -250,6 +343,8 @@ void example_lvgl_demo_ui(lv_disp_t *disp) { lv_example_bar_6(scr); gui_status_bar_create(scr); + + gui_create_value_setting_panel(); } static void gui_tick(void *pvParameters) { diff --git a/main/main.c b/main/main.c index bb7812e..902970e 100644 --- a/main/main.c +++ b/main/main.c @@ -14,7 +14,7 @@ #include "service_discovery.c" // #include "temperature.c" #include "udp_server.c" -// #include "ui_input.c" +#include "ui_input.c" #include "wifi.c" static const char *APP_TAG = "DisplayAmbientLight"; @@ -23,7 +23,7 @@ void app_main(void) { app_nvs_init(); light_init_strip(); - // gpio_install_isr_service(0); + gpio_install_isr_service(0); init_i2c(); i2c_check_slaves(); @@ -39,8 +39,8 @@ void app_main(void) { // apds_9960_init(); // apds_9960_auto_fetch(); // auto_fetch_temperature(); - // pca9555_init(); - // ui_input_init(); + pca9555_init(); + ui_input_init(); // xTaskCreate(mqtt_publish_ui_input, "mqtt_publish_ui_input", 2048, NULL, 10, // NULL); // vTaskDelay(pdMS_TO_TICKS(10)); diff --git a/main/pca9555.c b/main/pca9555.c index 9c351d5..8229d73 100644 --- a/main/pca9555.c +++ b/main/pca9555.c @@ -3,7 +3,6 @@ #include #include "driver/i2c.h" -#include "embedded_display.c" #include "esp_log.h" #include "i2c.c" @@ -79,19 +78,15 @@ void pca9555_fetch(void* arg) { esp_err_t error; uint8_t buff; char disp_str[17]; - display_fill_rect(0, 6, 128, 8, 0x00); for (;;) { error = pca9555_read_one_input(PCA95555_CMD_INPUT_PORT_1, &buff); if (error != ESP_OK) { ESP_LOGW(PCA_9555_TAG, "read failed. %x", error); } else { - sprintf(disp_str, "IO0: 0x%2x ", buff); - display_print8_str(8, 6, disp_str); ESP_LOGD(PCA_9555_TAG, "IO0: 0x%2x", buff); } vTaskDelay(pdMS_TO_TICKS(10)); } - display_fill_rect(0, 6, 128, 8, 0x00); } void pca9555_auto_fetch() { diff --git a/main/ui_input.c b/main/ui_input.c index 425c6da..a69ef6e 100644 --- a/main/ui_input.c +++ b/main/ui_input.c @@ -6,10 +6,10 @@ #include "config_key.h" #include "driver/gpio.h" -#include "embedded_display.c" #include "freertos/FreeRTOS.h" #include "freertos/queue.h" #include "freertos/task.h" +#include "gui.c" #include "light.c" #include "pca9555.c" @@ -72,7 +72,6 @@ static void ui_input_update_embedded_display(void *arg) { sprintf(changing_str, "CVol: % 3d", input.value); break; case ui_input_key_display_ambient_lighting_level: - sprintf(changing_str, "ALLv: % 3d", display_ambient_lighting_level); break; case ui_input_key_display_ambient_lighting_mode: sprintf(changing_str, "ALMd: % 3d", input.value); @@ -88,8 +87,6 @@ static void ui_input_update_embedded_display(void *arg) { strcpy(changing_str, "NC"); break; } - display_fill_rect(0, 6, 128, 8, 0); - display_print8_str(8, 6, changing_str); } } } @@ -161,6 +158,7 @@ static void encoder_value_change(encoder_state_t *state) { if (state->value & 1) { event.key = ui_input_key_display_ambient_lighting_level; led_strip_set_brightness(display_ambient_lighting_level + delta); + gui_change_strip_level(display_ambient_lighting_level); } else { event.key = ui_input_key_display_1_brightness; } From ca9e25f40c8a7c7c08ac5baeb0613dd9522a2ee1 Mon Sep 17 00:00:00 2001 From: Ivan Li Date: Wed, 3 May 2023 20:43:33 +0800 Subject: [PATCH 5/5] chore: change bar value label font size. --- main/gui.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/main/gui.c b/main/gui.c index 4fe4ee1..78b3e07 100644 --- a/main/gui.c +++ b/main/gui.c @@ -185,7 +185,7 @@ static void gui_bar_value_update_cb(lv_event_t *e) { lv_draw_label_dsc_t label_dsc; lv_draw_label_dsc_init(&label_dsc); - label_dsc.font = &lv_font_montserrat_8; + label_dsc.font = &lv_font_montserrat_10; char buf[8]; lv_snprintf(buf, sizeof(buf), "%ld", lv_bar_get_value(obj)); @@ -209,8 +209,6 @@ static void gui_bar_value_update_cb(lv_event_t *e) { LV_PART_MAIN); } - ESP_LOGI(GUI_TAG, "value_setting_value_label: %s", buf); - lv_obj_align(value_setting_value_label, LV_ALIGN_LEFT_MID, txt_x, 0); lv_label_set_text(value_setting_value_label, buf); lv_obj_set_width(value_setting_value_label, txt_size.x); @@ -252,7 +250,7 @@ static void gui_create_value_setting_panel() { value_setting_value_label = lv_label_create(value_setting_bar); lv_obj_align(value_setting_value_label, LV_ALIGN_CENTER, 0, 0); - lv_obj_set_style_text_font(value_setting_value_label, &lv_font_montserrat_8, + lv_obj_set_style_text_font(value_setting_value_label, &lv_font_montserrat_10, LV_PART_MAIN); }