├── .clangd ├── .gitignore ├── .vscode └── settings.json ├── CMakeLists.txt ├── HLK-LD1125H-24Gen.pdf ├── README.md ├── STL files ├── mmWaveHLK-LD1125H.stl └── rotary-encoder-knob.stl ├── banner └── banner(320x100).gif ├── circuit diagram ├── HLK-LD1125H.png ├── circuit diagram.PNG └── cover1.png ├── dependencies.lock ├── main ├── CMakeLists.txt ├── Kconfig.projbuild ├── display │ ├── display.c │ ├── display.h │ ├── gc9a01.c │ ├── gc9a01.h │ ├── lv_font_montserrat_20.c │ ├── lvgl_demo_ui.c │ ├── lvgl_demo_ui.h │ ├── ui_font_wise60.c │ ├── ui_helpers.c │ ├── ui_helpers.h │ ├── ui_img_1321029331.c │ ├── ui_img_bg3_png.c │ ├── ui_img_bulb_png.c │ ├── ui_img_off_bulb_png.c │ ├── ui_img_patern3_png.c │ ├── ui_page.c │ └── ui_page.h ├── esp_interrupt.c ├── esp_interrupt.h ├── gpio │ ├── gpio_config.c │ └── gpio_config.h ├── hardware │ ├── button.c │ ├── button.h │ ├── hlk-ld1125h.c │ ├── hlk-ld1125h.h │ ├── rotary_encoder.c │ └── rotary_encoder.h ├── idf_component.yml ├── main.c ├── main.h ├── timer │ ├── systimer.c │ └── systimer.h ├── uart_config.c ├── uart_config.h └── wireless │ ├── mqtt.c │ ├── mqtt.h │ ├── sntp.c │ ├── sntp.h │ ├── wifi_connect.c │ └── wifi_connect.h └── partitions.csv /.clangd: -------------------------------------------------------------------------------- 1 | CompileFlags: 2 | CompilationDatabase: build 3 | Remove: [-m*, -f*] 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | components/ 3 | managed_components/ 4 | 5 | sdkconfig 6 | sdkconfig.old 7 | sdkconfig.defaults 8 | 9 | .project 10 | .cproject 11 | main/.cproject 12 | main/.project -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "idf.adapterTargetName": "esp32s3", 3 | "files.associations": { 4 | "button.h": "c", 5 | "stdbool.h": "c", 6 | "hlk-ld1125h.h": "c", 7 | "gpio_config.h": "c", 8 | "string.h": "c", 9 | "display.h": "c", 10 | "lvgl.h": "c", 11 | "lvgl_demo_ui.h": "c" 12 | }, 13 | "idf.flashType": "UART" 14 | } -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.16) 2 | 3 | # This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. 4 | set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) 5 | 6 | include($ENV{IDF_PATH}/tools/cmake/project.cmake) 7 | project(spi_lcd_touch) 8 | -------------------------------------------------------------------------------- /HLK-LD1125H-24Gen.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UsefulElectronics/esp32s3-gc9a01-lvgl/f547f4b6044e65ddacd2d347b9a2102d2169ee39/HLK-LD1125H-24Gen.pdf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | [![Build Status](https://img.shields.io/badge/USEFUL%20ELECTRONICS-YOUTUBE-red)](https://www.youtube.com/user/wardzx1) 3 | 4 | # Sponsors 5 | 6 | ### PCBWay 7 | Tutorial Series Sponsor PCBWay Website. You can get extra free coupons using the link below: 8 | https://www.pcbway.com/setinvite.aspx?inviteid=582640 9 | 10 | *** 11 | 12 | # ESP32S3 Interfacing Rotary Encoder and GC9A01 TFT Rounded Display with LVGL 13 | *** 14 | ### [Tutorial Link](https://youtu.be/77VYMpIAbq4) On [![Build Status](https://img.shields.io/badge/YouTube-FF0000?style=for-the-badge&logo=youtube&logoColor=white)](https://www.youtube.com/wardzx1) 15 | 16 | In this tutorial, Rotary encoder is interfaced with ESP32S3 pulse counter peripheral that allows obtaining the position and rotation direction of the rotary encoder using 2 pins. 17 | 18 | The obtained rotary encoder position value is shown on GC9A01 rounded display using LVGL library. 19 | 20 | The working principle of rotary encoder and involved hardware is explained in details with the used code. 21 | ![Circuit Diagram](https://github.com/UsefulElectronics/esp32s3-gc9a01-lvgl/blob/main/circuit%20diagram/cover1.png) 22 | *** 23 | 24 | # ESP32S3 GC9A01 LVGL Smart Watch 25 | *** 26 | ### [Tutorial Link](https://youtu.be/Td08fweKXwY) On [![Build Status](https://img.shields.io/badge/YouTube-FF0000?style=for-the-badge&logo=youtube&logoColor=white)](https://www.youtube.com/wardzx1) 27 | 28 | In this tutorial, ESP32S3 MCU is used to display time and temperature data on a round display with a nice looking user interface that is designed using LVGL library with the help of Squareline Studio. 29 | 30 | SNTP is used in order to get real time data over TCP connection with WiFi. The MCU processes the data and prints it on the GC9A01 display that is interfaced over SPI protocol. 31 | 32 | Temperature data, on the other hand, is obtained over MQTT connection with Node-Red that is running on a raspberry pi, Which takes a request from an MQTT topic to send HTTP GET request OpenWeather API to obtain weather related string and then filter out the JSON file to get only the temperature data to publish it to an MQTT topic that the ESP32S3 is subscribed to. 33 | 34 | Every part regarding the user interface design is also explained in details using SquareLine Studio. 35 | ![Circuit Diagram](https://github.com/UsefulElectronics/esp32s3-gc9a01-lvgl/blob/main/circuit%20diagram/circuit%20diagram.PNG) 36 | *** 37 | 38 | # ESP32S3 HLK-LD1125H Human Presence Sensor 39 | *** 40 | ### [Tutorial Link](https://youtu.be/RXj-JX6W-YE) On [![Build Status](https://img.shields.io/badge/YouTube-FF0000?style=for-the-badge&logo=youtube&logoColor=white)](https://www.youtube.com/wardzx1) 41 | 42 | In this tutorial, ESP32S3 MCU is programmed to show Human Presence Radar data that is received over UART on GC9A01 round display that is driven over SPI. 43 | 44 | The human presence radar continuously sends detected object distance and its movement type. the MCU takes the data converts it and prints it on the round display. 45 | 46 | The nicely looking user interface is designed using Square line studio with LVGL library. 47 | 48 | The radar module is tested to detect moving objects and human behind obstacle like door or wall. check out the test results. 49 | 50 | Reach out the Radar datasheet form this [link](https://github.com/UsefulElectronics/esp32s3-gc9a01-lvgl/blob/main/HLK-LD1125H-24Gen.pdf). 51 | 52 | ![Circuit Diagram](https://github.com/UsefulElectronics/esp32s3-gc9a01-lvgl/blob/main/circuit%20diagram/HLK-LD1125H.png) 53 | 54 | | Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-S2 | ESP32-S3 | 55 | | ----------------- | ----- | -------- | -------- | -------- | -------- | 56 | 57 | # SPI LCD and Touch Panel Example 58 | 59 | [esp_lcd](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/lcd.html) provides several panel drivers out-of box, e.g. ST7789, SSD1306, NT35510. However, there're a lot of other panels on the market, it's beyond `esp_lcd` component's responsibility to include them all. 60 | 61 | `esp_lcd` allows user to add their own panel drivers in the project scope (i.e. panel driver can live outside of esp-idf), so that the upper layer code like LVGL porting code can be reused without any modifications, as long as user-implemented panel driver follows the interface defined in the `esp_lcd` component. 62 | 63 | This example shows how to use GC9A01 or ILI9341 display driver from Component manager in esp-idf project. These components are using API provided by `esp_lcd` component. This example will draw a fancy dash board with the LVGL library. For more information about porting the LVGL library, you can also refer to [another lvgl porting example](../i80_controller/README.md). 64 | 65 | ## Touch controller STMPE610 66 | 67 | In this example you can enable touch controller STMPE610 connected via SPI. The SPI connection is shared with LCD screen. 68 | 69 | ## How to use the example 70 | 71 | ### Hardware Required 72 | 73 | * An ESP development board 74 | * An GC9A01 or ILI9341 LCD panel, with SPI interface (with/without STMPE610 SPI touch) 75 | * An USB cable for power supply and programming 76 | 77 | ### Hardware Connection 78 | 79 | The connection between ESP Board and the LCD is as follows: 80 | 81 | ``` 82 | ESP Board GC9A01/ILI9341 Panel + TOUCH 83 | ┌──────────────────────┐ ┌────────────────────┐ 84 | │ GND ├─────────────►│ GND │ 85 | │ │ │ │ 86 | │ 3V3 ├─────────────►│ VCC │ 87 | │ │ │ │ 88 | │ PCLK ├─────────────►│ SCL │ 89 | │ │ │ │ 90 | │ MOSI ├─────────────►│ MOSI │ 91 | │ │ │ │ 92 | │ MISO |◄─────────────┤ MISO │ 93 | │ │ │ │ 94 | │ RST ├─────────────►│ RES │ 95 | │ │ │ │ 96 | │ DC ├─────────────►│ DC │ 97 | │ │ │ │ 98 | │ LCD CS ├─────────────►│ LCD CS │ 99 | │ │ │ │ 100 | │ TOUCH CS ├─────────────►│ TOUCH CS │ 101 | │ │ │ │ 102 | │ BK_LIGHT ├─────────────►│ BLK │ 103 | └──────────────────────┘ └────────────────────┘ 104 | ``` 105 | 106 | The GPIO number used by this example can be changed in [lvgl_example_main.c](main/spi_lcd_touch_example_main.c). 107 | Especially, please pay attention to the level used to turn on the LCD backlight, some LCD module needs a low level to turn it on, while others take a high level. You can change the backlight level macro `EXAMPLE_LCD_BK_LIGHT_ON_LEVEL` in [lvgl_example_main.c](main/spi_lcd_touch_example_main.c). 108 | 109 | ### Build and Flash 110 | 111 | Run `idf.py -p PORT build flash monitor` to build, flash and monitor the project. A fancy animation will show up on the LCD as expected. 112 | 113 | The first time you run `idf.py` for the example will cost extra time as the build system needs to address the component dependencies and downloads the missing components from registry into `managed_components` folder. 114 | 115 | (To exit the serial monitor, type ``Ctrl-]``.) 116 | 117 | See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects. 118 | 119 | ### Example Output 120 | 121 | ```bash 122 | ... 123 | I (409) cpu_start: Starting scheduler on APP CPU. 124 | I (419) example: Turn off LCD backlight 125 | I (419) gpio: GPIO[2]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 126 | I (429) example: Initialize SPI bus 127 | I (439) example: Install panel IO 128 | I (439) gpio: GPIO[5]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 129 | I (449) example: Install GC9A01 panel driver 130 | I (459) gpio: GPIO[3]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 131 | I (589) gpio: GPIO[0]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 132 | I (589) example: Initialize touch controller STMPE610 133 | I (589) STMPE610: TouchPad ID: 0x0811 134 | I (589) STMPE610: TouchPad Ver: 0x03 135 | I (599) example: Turn on LCD backlight 136 | I (599) example: Initialize LVGL library 137 | I (609) example: Register display driver to LVGL 138 | I (619) example: Install LVGL tick timer 139 | I (619) example: Display LVGL Meter Widget 140 | ... 141 | ``` 142 | -------------------------------------------------------------------------------- /STL files/mmWaveHLK-LD1125H.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UsefulElectronics/esp32s3-gc9a01-lvgl/f547f4b6044e65ddacd2d347b9a2102d2169ee39/STL files/mmWaveHLK-LD1125H.stl -------------------------------------------------------------------------------- /banner/banner(320x100).gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UsefulElectronics/esp32s3-gc9a01-lvgl/f547f4b6044e65ddacd2d347b9a2102d2169ee39/banner/banner(320x100).gif -------------------------------------------------------------------------------- /circuit diagram/HLK-LD1125H.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UsefulElectronics/esp32s3-gc9a01-lvgl/f547f4b6044e65ddacd2d347b9a2102d2169ee39/circuit diagram/HLK-LD1125H.png -------------------------------------------------------------------------------- /circuit diagram/circuit diagram.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UsefulElectronics/esp32s3-gc9a01-lvgl/f547f4b6044e65ddacd2d347b9a2102d2169ee39/circuit diagram/circuit diagram.PNG -------------------------------------------------------------------------------- /circuit diagram/cover1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UsefulElectronics/esp32s3-gc9a01-lvgl/f547f4b6044e65ddacd2d347b9a2102d2169ee39/circuit diagram/cover1.png -------------------------------------------------------------------------------- /dependencies.lock: -------------------------------------------------------------------------------- 1 | dependencies: 2 | espressif/cmake_utilities: 3 | component_hash: 351350613ceafba240b761b4ea991e0f231ac7a9f59a9ee901f751bddc0bb18f 4 | source: 5 | type: service 6 | version: 0.5.3 7 | espressif/esp_lcd_gc9a01: 8 | component_hash: 2ccbdfa5a1762c7a8be66770b69a256d809651d6069098852d2c829648707b5b 9 | source: 10 | type: service 11 | version: 1.2.0 12 | espressif/esp_lcd_ili9341: 13 | component_hash: 31f1b793aa2110dd2ae071c21ccbff0a4eb20d9a4ee40b6294c0dc0ad9552c4e 14 | source: 15 | type: service 16 | version: 1.2.0 17 | espressif/esp_lcd_touch: 18 | component_hash: 779b4ba2464a3ae85681e4b860caa5fdc35801458c23f3039ee761bae7f442a4 19 | source: 20 | type: service 21 | version: 1.1.2 22 | espressif/esp_lcd_touch_stmpe610: 23 | component_hash: 0f5f7fb50c2d716e72c2729725e4f96232a594d4b36036d6faa74e66e24d2ac9 24 | source: 25 | type: service 26 | version: 1.0.6 27 | idf: 28 | component_hash: null 29 | source: 30 | type: idf 31 | version: 5.3.0 32 | lvgl/lvgl: 33 | component_hash: 948bff879a345149b83065535bbc4a026ce9f47498a22881e432a264b9098015 34 | source: 35 | type: service 36 | version: 8.3.11 37 | manifest_hash: adae49024d5cf6de4a99c6ff31ffdfe50c04e1cc7514c510f3497dab9d199b1a 38 | target: esp32s3 39 | version: 1.0.0 40 | -------------------------------------------------------------------------------- /main/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | idf_component_register( 2 | SRCS "main.c" 3 | SRCS "uart_config.c" 4 | SRCS "esp_interrupt.c" 5 | 6 | SRCS "hardware/rotary_encoder.c" 7 | SRCS "hardware/hlk-ld1125h.c" 8 | SRCS "hardware/button.c" 9 | SRCS "wireless/sntp.c" 10 | SRCS "wireless/mqtt.c" 11 | SRCS "wireless/wifi_connect.c" 12 | SRCS "display/ui_img_patern3_png.c" 13 | SRCS "display/ui_helpers.c" 14 | SRCS "display/ui_font_wise60.c" 15 | SRCS "display/ui_img_1321029331.c" 16 | SRCS "display/ui_img_bg3_png.c" 17 | SRCS "display/ui_img_off_bulb_png.c" 18 | SRCS "display/ui_img_bulb_png.c" 19 | SRCS "display/lv_font_montserrat_20.c" 20 | SRCS "display/lvgl_demo_ui.c" 21 | SRCS "display/display.c" 22 | SRCS "display/gc9a01.c" 23 | SRCS "gpio/gpio_config.c" 24 | SRCS "timer/systimer.c" 25 | INCLUDE_DIRS ".") 26 | -------------------------------------------------------------------------------- /main/Kconfig.projbuild: -------------------------------------------------------------------------------- 1 | menu "Example Configuration" 2 | 3 | choice EXAMPLE_LCD_CONTROLLER 4 | prompt "LCD controller model" 5 | default EXAMPLE_LCD_CONTROLLER_ILI9341 6 | help 7 | Select LCD controller model 8 | 9 | config EXAMPLE_LCD_CONTROLLER_ILI9341 10 | bool "ILI9341" 11 | 12 | config EXAMPLE_LCD_CONTROLLER_GC9A01 13 | bool "GC9A01" 14 | endchoice 15 | 16 | config EXAMPLE_LCD_TOUCH_ENABLED 17 | bool "Enable LCD touch" 18 | default n 19 | help 20 | Enable this option if you wish to use display touch. You can select from touch controllers. 21 | 22 | choice EXAMPLE_LCD_TOUCH_CONTROLLER 23 | prompt "LCD touch controller model" 24 | depends on EXAMPLE_LCD_TOUCH_ENABLED 25 | default EXAMPLE_LCD_TOUCH_CONTROLLER_STMPE610 26 | help 27 | Select LCD touch controller model 28 | 29 | config EXAMPLE_LCD_TOUCH_CONTROLLER_STMPE610 30 | bool "STMPE610" 31 | help 32 | Touch controller STMPE610 connected via SPI. 33 | endchoice 34 | 35 | endmenu 36 | -------------------------------------------------------------------------------- /main/display/display.c: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * USEFUL ELECTRONICS 4 | ******************************************************************************/ 5 | /** 6 | ****************************************************************************** 7 | * @file : display.c 8 | * @author : WARD ALMASARANI 9 | * @version : v.1.0 10 | * @date : Feb 1, 2023 11 | * @link : https://www.youtube.com/@usefulelectronics 12 | * Hold Ctrl button and click on the link to be directed to 13 | Useful Electronics YouTube channel 14 | ******************************************************************************/ 15 | 16 | 17 | /* INCLUDES ------------------------------------------------------------------*/ 18 | #include "display.h" 19 | 20 | 21 | /* PRIVATE STRUCTRES ---------------------------------------------------------*/ 22 | 23 | /* VARIABLES -----------------------------------------------------------------*/ 24 | lv_disp_drv_t disp_drv; // contains callback functions 25 | /* DEFINITIONS ---------------------------------------------------------------*/ 26 | 27 | /* MACROS --------------------------------------------------------------------*/ 28 | static const char *TAG = "example"; 29 | /* PRIVATE FUNCTIONS DECLARATION ---------------------------------------------*/ 30 | extern void example_lvgl_demo_ui(lv_disp_t *disp); 31 | /* FUNCTION PROTOTYPES -------------------------------------------------------*/ 32 | 33 | 34 | bool display_notify_lvgl_flush_ready(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx) 35 | { 36 | lv_disp_drv_t *disp_driver = (lv_disp_drv_t *)user_ctx; 37 | lv_disp_flush_ready(disp_driver); 38 | return false; 39 | } 40 | 41 | static void example_lvgl_flush_cb(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map) 42 | { 43 | esp_lcd_panel_handle_t panel_handle = (esp_lcd_panel_handle_t) drv->user_data; 44 | int offsetx1 = area->x1; 45 | int offsetx2 = area->x2; 46 | int offsety1 = area->y1; 47 | int offsety2 = area->y2; 48 | // copy a buffer's content to a specific area of the display 49 | esp_lcd_panel_draw_bitmap(panel_handle, offsetx1, offsety1, offsetx2 + 1, offsety2 + 1, color_map); 50 | } 51 | 52 | /* Rotate display and touch, when rotated screen in LVGL. Called when driver parameters are updated. */ 53 | static void example_lvgl_port_update_callback(lv_disp_drv_t *drv) 54 | { 55 | esp_lcd_panel_handle_t panel_handle = (esp_lcd_panel_handle_t) drv->user_data; 56 | 57 | switch (drv->rotated) { 58 | case LV_DISP_ROT_NONE: 59 | // Rotate LCD display 60 | esp_lcd_panel_swap_xy(panel_handle, false); 61 | esp_lcd_panel_mirror(panel_handle, true, false); 62 | 63 | break; 64 | case LV_DISP_ROT_90: 65 | // Rotate LCD display 66 | esp_lcd_panel_swap_xy(panel_handle, true); 67 | esp_lcd_panel_mirror(panel_handle, true, true); 68 | 69 | break; 70 | case LV_DISP_ROT_180: 71 | // Rotate LCD display 72 | esp_lcd_panel_swap_xy(panel_handle, false); 73 | esp_lcd_panel_mirror(panel_handle, false, true); 74 | 75 | break; 76 | case LV_DISP_ROT_270: 77 | // Rotate LCD display 78 | esp_lcd_panel_swap_xy(panel_handle, true); 79 | esp_lcd_panel_mirror(panel_handle, false, false); 80 | 81 | break; 82 | } 83 | } 84 | 85 | 86 | 87 | static void example_increase_lvgl_tick(void *arg) 88 | { 89 | /* Tell LVGL how many milliseconds has elapsed */ 90 | lv_tick_inc(EXAMPLE_LVGL_TICK_PERIOD_MS); 91 | } 92 | 93 | 94 | void displayConfig(void) 95 | { 96 | static lv_disp_draw_buf_t disp_buf; // contains internal graphic buffer(s) called draw buffer(s) 97 | 98 | 99 | 100 | 101 | ESP_LOGI(TAG, "Initialize LVGL library"); 102 | lv_init(); 103 | // alloc draw buffers used by LVGL 104 | // it's recommended to choose the size of the draw buffer(s) to be at least 1/10 screen sized 105 | lv_color_t *buf1 = heap_caps_malloc(EXAMPLE_LCD_H_RES * 20 * sizeof(lv_color_t), MALLOC_CAP_DMA); 106 | assert(buf1); 107 | lv_color_t *buf2 = heap_caps_malloc(EXAMPLE_LCD_H_RES * 20 * sizeof(lv_color_t), MALLOC_CAP_DMA); 108 | assert(buf2); 109 | // initialize LVGL draw buffers 110 | lv_disp_draw_buf_init(&disp_buf, buf1, buf2, EXAMPLE_LCD_H_RES * 20); 111 | 112 | ESP_LOGI(TAG, "Register display driver to LVGL"); 113 | lv_disp_drv_init(&disp_drv); 114 | disp_drv.hor_res = EXAMPLE_LCD_H_RES; 115 | disp_drv.ver_res = EXAMPLE_LCD_V_RES; 116 | disp_drv.flush_cb = example_lvgl_flush_cb; 117 | disp_drv.drv_update_cb = example_lvgl_port_update_callback; 118 | disp_drv.draw_buf = &disp_buf; 119 | disp_drv.user_data = panel_handle; 120 | lv_disp_t *disp = lv_disp_drv_register(&disp_drv); 121 | 122 | ESP_LOGI(TAG, "Install LVGL tick timer"); 123 | // Tick interface for LVGL (using esp_timer to generate 2ms periodic event) 124 | const esp_timer_create_args_t lvgl_tick_timer_args = { 125 | .callback = &example_increase_lvgl_tick, 126 | .name = "lvgl_tick" 127 | }; 128 | esp_timer_handle_t lvgl_tick_timer = NULL; 129 | ESP_ERROR_CHECK(esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer)); 130 | ESP_ERROR_CHECK(esp_timer_start_periodic(lvgl_tick_timer, EXAMPLE_LVGL_TICK_PERIOD_MS * 1000)); 131 | 132 | 133 | ESP_LOGI(TAG, "Display LVGL Meter Widget"); 134 | example_lvgl_demo_ui(disp); 135 | 136 | } 137 | /*************************************** USEFUL ELECTRONICS*****END OF FILE****/ 138 | -------------------------------------------------------------------------------- /main/display/display.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * USEFUL ELECTRONICS 4 | ******************************************************************************/ 5 | /** 6 | ****************************************************************************** 7 | * @file : display.h 8 | * @author : WARD ALMASARANI 9 | * @version : v.1.0 10 | * @date : Feb 1, 2023 11 | * @link : https://www.youtube.com/@usefulelectronics 12 | * Hold Ctrl button and click on the link to be directed to 13 | Useful Electronics YouTube channel 14 | ******************************************************************************/ 15 | 16 | #ifndef MAIN_DISPLAY_H_ 17 | #define MAIN_DISPLAY_H_ 18 | 19 | 20 | /* INCLUDES ------------------------------------------------------------------*/ 21 | #include "gc9a01.h" 22 | 23 | #include "esp_err.h" 24 | #include "esp_log.h" 25 | #include "lvgl.h" 26 | /* MACROS --------------------------------------------------------------------*/ 27 | #define EXAMPLE_LVGL_TICK_PERIOD_MS 2 28 | /* ENUMORATIONS --------------------------------------------------------------*/ 29 | 30 | /* STRUCTURES & TYPEDEFS -----------------------------------------------------*/ 31 | 32 | /* VARIABLES -----------------------------------------------------------------*/ 33 | extern lv_disp_drv_t disp_drv; 34 | /* FUNCTIONS DECLARATION -----------------------------------------------------*/ 35 | bool display_notify_lvgl_flush_ready(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx); 36 | 37 | void displayConfig(void); 38 | #endif /* MAIN_DISPLAY_H_ */ 39 | 40 | /*************************************** USEFUL ELECTRONICS*****END OF FILE****/ 41 | -------------------------------------------------------------------------------- /main/display/gc9a01.c: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * USEFUL ELECTRONICS 4 | ******************************************************************************/ 5 | /** 6 | ****************************************************************************** 7 | * @file : gc9a01.c 8 | * @author : WARD ALMASARANI 9 | * @version : v.1.0 10 | * @date : Jan 31, 2023 11 | * @link : https://www.youtube.com/@usefulelectronics 12 | * Hold Ctrl button and click on the link to be directed to 13 | Useful Electronics YouTube channel 14 | ******************************************************************************/ 15 | 16 | 17 | /* INCLUDES ------------------------------------------------------------------*/ 18 | #include "gc9a01.h" 19 | #include "display.h" 20 | /* PRIVATE STRUCTRES ---------------------------------------------------------*/ 21 | 22 | /* VARIABLES -----------------------------------------------------------------*/ 23 | 24 | static const char *gc9a01 = "display"; 25 | 26 | esp_lcd_panel_handle_t panel_handle = NULL; 27 | /* DEFINITIONS ---------------------------------------------------------------*/ 28 | 29 | /* MACROS --------------------------------------------------------------------*/ 30 | 31 | /* PRIVATE FUNCTIONS DECLARATION ---------------------------------------------*/ 32 | 33 | /* FUNCTION PROTOTYPES -------------------------------------------------------*/ 34 | void gc9a01_displayInit(void) 35 | { 36 | ESP_LOGI(gc9a01, "Turn off LCD backlight"); 37 | gpio_config_t bk_gpio_config = { 38 | .mode = GPIO_MODE_OUTPUT, 39 | .pin_bit_mask = 1ULL << EXAMPLE_PIN_NUM_BK_LIGHT 40 | }; 41 | ESP_ERROR_CHECK(gpio_config(&bk_gpio_config)); 42 | 43 | ESP_LOGI(gc9a01, "Initialize SPI bus"); 44 | spi_bus_config_t buscfg = { 45 | .sclk_io_num = EXAMPLE_PIN_NUM_SCLK, 46 | .mosi_io_num = EXAMPLE_PIN_NUM_MOSI, 47 | .miso_io_num = EXAMPLE_PIN_NUM_MISO, 48 | .quadwp_io_num = -1, 49 | .quadhd_io_num = -1, 50 | .max_transfer_sz = EXAMPLE_LCD_H_RES * 80 * sizeof(uint16_t), 51 | }; 52 | ESP_ERROR_CHECK(spi_bus_initialize(LCD_HOST, &buscfg, SPI_DMA_CH_AUTO)); 53 | 54 | ESP_LOGI(gc9a01, "Install panel IO"); 55 | esp_lcd_panel_io_handle_t io_handle = NULL; 56 | esp_lcd_panel_io_spi_config_t io_config = { 57 | .dc_gpio_num = EXAMPLE_PIN_NUM_LCD_DC, 58 | .cs_gpio_num = EXAMPLE_PIN_NUM_LCD_CS, 59 | .pclk_hz = EXAMPLE_LCD_PIXEL_CLOCK_HZ, 60 | .lcd_cmd_bits = EXAMPLE_LCD_CMD_BITS, 61 | .lcd_param_bits = EXAMPLE_LCD_PARAM_BITS, 62 | .spi_mode = 0, 63 | .trans_queue_depth = 10, 64 | .on_color_trans_done = display_notify_lvgl_flush_ready, 65 | .user_ctx = &disp_drv, 66 | }; 67 | // Attach the LCD to the SPI bus 68 | ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)LCD_HOST, &io_config, &io_handle)); 69 | 70 | ESP_LOGI(gc9a01, "Install GC9A01 panel driver"); 71 | 72 | esp_lcd_panel_dev_config_t panel_config = { 73 | .reset_gpio_num = EXAMPLE_PIN_NUM_LCD_RST, 74 | 75 | //.rgb_endian = LCD_RGB_ENDIAN_RGB, LCD_RGB_ENDIAN_BGR 76 | 77 | //.rgb_ele_order = LCD_RGB_ENDIAN_RGB, 78 | .rgb_endian = LCD_RGB_ENDIAN_BGR, 79 | 80 | .bits_per_pixel = 16, 81 | }; 82 | 83 | 84 | ESP_ERROR_CHECK(esp_lcd_new_panel_gc9a01(io_handle, &panel_config, &panel_handle)); 85 | 86 | 87 | ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle)); 88 | ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle)); 89 | 90 | ESP_ERROR_CHECK(esp_lcd_panel_invert_color(panel_handle, true)); 91 | 92 | ESP_ERROR_CHECK(esp_lcd_panel_mirror(panel_handle, true, false)); 93 | 94 | // user can flush pre-defined pattern to the screen before we turn on the screen or backlight 95 | ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true)); 96 | 97 | 98 | ESP_LOGI(gc9a01, "Turn on LCD backlight"); 99 | gpio_set_level(EXAMPLE_PIN_NUM_BK_LIGHT, EXAMPLE_LCD_BK_LIGHT_ON_LEVEL); 100 | 101 | 102 | } 103 | 104 | /*************************************** USEFUL ELECTRONICS*****END OF FILE****/ 105 | -------------------------------------------------------------------------------- /main/display/gc9a01.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * USEFUL ELECTRONICS 4 | ******************************************************************************/ 5 | /** 6 | ****************************************************************************** 7 | * @file : gc9a01.h 8 | * @author : WARD ALMASARANI 9 | * @version : v.1.0 10 | * @date : Jan 31, 2023 11 | * @link : https://www.youtube.com/@usefulelectronics 12 | * Hold Ctrl button and click on the link to be directed to 13 | Useful Electronics YouTube channel 14 | ******************************************************************************/ 15 | 16 | #ifndef MAIN_GC9A01_H_ 17 | #define MAIN_GC9A01_H_ 18 | 19 | 20 | /* INCLUDES ------------------------------------------------------------------*/ 21 | #include "esp_lcd_gc9a01.h" 22 | 23 | #include 24 | #include "freertos/FreeRTOS.h" 25 | #include "freertos/task.h" 26 | #include "esp_timer.h" 27 | #include "esp_lcd_panel_io.h" 28 | #include "esp_lcd_panel_vendor.h" 29 | #include "esp_lcd_panel_ops.h" 30 | #include "driver/gpio.h" 31 | #include "driver/spi_master.h" 32 | 33 | #include "esp_err.h" 34 | #include "esp_log.h" 35 | /* MACROS --------------------------------------------------------------------*/ 36 | // Using SPI2 in the example 37 | #define LCD_HOST SPI2_HOST 38 | 39 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 40 | //////////////////// Please update the following configuration according to your LCD spec ////////////////////////////// 41 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 42 | #define EXAMPLE_LCD_PIXEL_CLOCK_HZ (20 * 1000 * 1000) 43 | #define EXAMPLE_LCD_BK_LIGHT_ON_LEVEL 1 44 | #define EXAMPLE_LCD_BK_LIGHT_OFF_LEVEL !EXAMPLE_LCD_BK_LIGHT_ON_LEVEL 45 | #define EXAMPLE_PIN_NUM_SCLK 14//4//18 46 | #define EXAMPLE_PIN_NUM_MOSI 13//5//19 47 | #define EXAMPLE_PIN_NUM_MISO 12//21 48 | #define EXAMPLE_PIN_NUM_LCD_DC 21///5 49 | #define EXAMPLE_PIN_NUM_LCD_RST 11//15 50 | #define EXAMPLE_PIN_NUM_LCD_CS 15//7//4 51 | #define EXAMPLE_PIN_NUM_BK_LIGHT 7// 18//2 52 | #define EXAMPLE_PIN_NUM_TOUCH_CS 17//15 53 | 54 | #define EXAMPLE_LCD_H_RES 240 55 | #define EXAMPLE_LCD_V_RES 240 56 | 57 | #define EXAMPLE_LCD_CMD_BITS 8 58 | #define EXAMPLE_LCD_PARAM_BITS 8 59 | 60 | 61 | 62 | /* ENUMORATIONS --------------------------------------------------------------*/ 63 | 64 | /* STRUCTURES & TYPEDEFS -----------------------------------------------------*/ 65 | 66 | /* VARIABLES -----------------------------------------------------------------*/ 67 | extern esp_lcd_panel_handle_t panel_handle; 68 | /* FUNCTIONS DECLARATION -----------------------------------------------------*/ 69 | void gc9a01_displayInit(void); 70 | 71 | 72 | #endif /* MAIN_GC9A01_H_ */ 73 | 74 | /*************************************** USEFUL ELECTRONICS*****END OF FILE****/ 75 | -------------------------------------------------------------------------------- /main/display/lvgl_demo_ui.c: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD 3 | * 4 | * SPDX-License-Identifier: CC0-1.0 5 | */ 6 | 7 | // This demo UI is adapted from LVGL official example: https://docs.lvgl.io/master/widgets/extra/meter.html#simple-meter 8 | 9 | #include "lvgl_demo_ui.h" 10 | #include "core/lv_obj.h" 11 | #include "extra/widgets/colorwheel/lv_colorwheel.h" 12 | 13 | 14 | static void ui_radar_screen_init(void); 15 | static void ui_watch_screen_init(void); 16 | static void ui_lamp_screen_init(void); 17 | 18 | static lv_obj_t *meter; 19 | static lv_obj_t * btn; 20 | static lv_disp_rot_t rotation = LV_DISP_ROT_NONE; 21 | static lv_disp_t *lv_display; 22 | static lv_meter_indicator_t *indic; 23 | static lv_style_t bgStyle; 24 | 25 | static lv_color_hsv_t ui_color_wheel_obj = {0}; 26 | 27 | watch_t realTime = {0}; 28 | 29 | //Smart watch screen 30 | lv_obj_t * ui_Screen1; 31 | lv_obj_t * ui_Arc2; 32 | lv_obj_t * ui_Panel2; 33 | lv_obj_t * ui_Panel1; 34 | lv_obj_t * ui_Label2; 35 | lv_obj_t * ui_Label3; 36 | lv_obj_t * ui_Label4; 37 | 38 | //Radar Screen 39 | lv_obj_t * ui_radar; 40 | lv_obj_t * ui_Panel6; 41 | lv_obj_t * ui_Arc3; 42 | lv_obj_t * ui_Panel7; 43 | lv_obj_t * ui_Distance; 44 | lv_obj_t * ui_MovementType; 45 | 46 | lv_obj_t *tv1; 47 | lv_obj_t *tv2; 48 | 49 | // SCREEN: ui_Lamp 50 | lv_obj_t * ui_lamp; 51 | lv_obj_t * ui_Panel9; 52 | lv_obj_t * ui_Switch1; 53 | lv_obj_t * ui_Switch3; 54 | lv_obj_t * ui_Colorwheel2; 55 | lv_obj_t * ui_Label4; 56 | lv_obj_t * ui_Label6; 57 | lv_obj_t * ui_Panel10; 58 | lv_obj_t * ui_Image8; 59 | lv_obj_t * ui_Image9; 60 | 61 | void ui_set_wheel_color(lv_color_hsv_t* hsv) 62 | { 63 | memcpy(&ui_color_wheel_obj, hsv, sizeof(lv_color_hsv_t)); 64 | 65 | lv_colorwheel_set_hsv(ui_Colorwheel2, *hsv); 66 | } 67 | 68 | void ui_set_wheel_mode(lv_colorwheel_mode_t mode) 69 | { 70 | lv_colorwheel_set_mode(ui_Colorwheel2, mode); 71 | } 72 | 73 | void ui_set_lamp_state(bool state) 74 | { 75 | //Control image hide flag depending on the passed state 76 | if(state) 77 | { 78 | lv_obj_clear_flag(ui_Image9, LV_OBJ_FLAG_HIDDEN); 79 | } 80 | else 81 | { 82 | lv_obj_add_flag(ui_Image9,LV_OBJ_FLAG_HIDDEN); 83 | } 84 | } 85 | 86 | void ui_set_wifi_switch_state(bool state) 87 | { 88 | if(state) 89 | { 90 | lv_obj_add_state(ui_Switch3, LV_STATE_CHECKED); 91 | 92 | } 93 | else 94 | { 95 | lv_obj_clear_state(ui_Switch3, LV_STATE_CHECKED); 96 | } 97 | } 98 | 99 | void ui_set_mqtt_switch_state(bool state) 100 | { 101 | if(state) 102 | { 103 | lv_obj_add_state(ui_Switch1, LV_STATE_CHECKED); 104 | 105 | } 106 | else 107 | { 108 | lv_obj_clear_state(ui_Switch1, LV_STATE_CHECKED); 109 | } 110 | } 111 | 112 | 113 | 114 | 115 | void set_value(int32_t v, bool buttonStatus) 116 | { 117 | lv_color_t bgColor; 118 | static bool toggleColor = 0; 119 | 120 | lv_obj_t *disObject = lv_disp_get_scr_act(lv_display); 121 | 122 | lv_meter_set_indicator_end_value(meter, indic, v); 123 | 124 | if(!buttonStatus) 125 | { 126 | toggleColor ^= 1; 127 | if(toggleColor) 128 | { 129 | //White 130 | bgColor = lv_color_hex(0xFFFFFF); 131 | } 132 | else 133 | { 134 | //black 135 | bgColor = lv_color_hex(0x000000); 136 | } 137 | lv_obj_add_style(disObject, &bgStyle, 0); 138 | lv_style_set_bg_color(&bgStyle, bgColor); 139 | } 140 | 141 | } 142 | 143 | void example_lvgl_demo_ui(lv_disp_t *disp) 144 | { 145 | lv_color_t bgColor; 146 | lv_display = disp; 147 | lv_obj_t *dis; 148 | lv_obj_t *scr = lv_disp_get_scr_act(disp); 149 | 150 | bgColor = lv_color_hex(0x101418); 151 | lv_style_init(&bgStyle); 152 | 153 | 154 | dis = lv_tileview_create(scr); 155 | lv_obj_align(dis, LV_ALIGN_TOP_RIGHT, 0, 0); 156 | 157 | ui_lamp = lv_tileview_add_tile(dis, 0, 0, LV_DIR_HOR); 158 | ui_radar = lv_tileview_add_tile(dis, 0, 2, LV_DIR_HOR); 159 | ui_Screen1 = lv_tileview_add_tile(dis, 0, 1, LV_DIR_HOR); 160 | 161 | 162 | //tv3 = lv_tileview_add_tile(dis, 0, 2, LV_DIR_HOR); 163 | 164 | // lv_obj_add_style(ui_Screen1, &bgStyle, 0); 165 | // lv_style_set_bg_color(&bgStyle, bgColor); 166 | 167 | //lv_obj_add_style(ui_radar, &bgStyle, 0); 168 | //lv_style_set_bg_color(&bgStyle, bgColor); 169 | 170 | lv_obj_add_style(ui_lamp, &bgStyle, 0); 171 | lv_style_set_bg_color(&bgStyle, bgColor); 172 | 173 | ui_lamp_screen_init(); 174 | //ui_radar_screen_init(); 175 | } 176 | 177 | static void ui_radar_screen_init(void) 178 | { 179 | 180 | // ui_radar = lv_obj_create(NULL); 181 | lv_obj_clear_flag(ui_radar, LV_OBJ_FLAG_SCROLLABLE); /// Flags 182 | 183 | ui_Panel6 = lv_obj_create(ui_radar); 184 | lv_obj_set_width(ui_Panel6, 220); 185 | lv_obj_set_height(ui_Panel6, 220); 186 | lv_obj_set_align(ui_Panel6, LV_ALIGN_CENTER); 187 | lv_obj_clear_flag(ui_Panel6, LV_OBJ_FLAG_SCROLLABLE); /// Flags 188 | lv_obj_set_style_radius(ui_Panel6, 360, LV_PART_MAIN | LV_STATE_DEFAULT); 189 | lv_obj_set_style_bg_color(ui_Panel6, lv_color_hex(0x0E0303), LV_PART_MAIN | LV_STATE_DEFAULT); 190 | lv_obj_set_style_bg_opa(ui_Panel6, 255, LV_PART_MAIN | LV_STATE_DEFAULT); 191 | lv_obj_set_style_bg_img_src(ui_Panel6, &ui_img_1321029331, LV_PART_MAIN | LV_STATE_DEFAULT); 192 | lv_obj_set_style_border_color(ui_Panel6, lv_color_hex(0x101418), LV_PART_MAIN | LV_STATE_DEFAULT); 193 | lv_obj_set_style_border_opa(ui_Panel6, 255, LV_PART_MAIN | LV_STATE_DEFAULT); 194 | lv_obj_set_style_border_side(ui_Panel6, LV_BORDER_SIDE_FULL, LV_PART_MAIN | LV_STATE_DEFAULT); 195 | 196 | ui_Arc3 = lv_arc_create(ui_radar); 197 | lv_obj_set_width(ui_Arc3, 240); 198 | lv_obj_set_height(ui_Arc3, 240); 199 | lv_obj_set_align(ui_Arc3, LV_ALIGN_CENTER); 200 | lv_obj_add_flag(ui_Arc3, LV_OBJ_FLAG_ADV_HITTEST); /// Flags 201 | lv_arc_set_range(ui_Arc3, 0, 360); 202 | lv_arc_set_bg_angles(ui_Arc3, 0, 360); 203 | lv_arc_set_rotation(ui_Arc3, 180); 204 | lv_obj_set_style_arc_color(ui_Arc3, lv_color_hex(0x101418), LV_PART_MAIN | LV_STATE_DEFAULT); 205 | lv_obj_set_style_arc_opa(ui_Arc3, 255, LV_PART_MAIN | LV_STATE_DEFAULT); 206 | 207 | lv_obj_set_style_arc_color(ui_Arc3, lv_color_hex(0xD20000), LV_PART_INDICATOR | LV_STATE_DEFAULT); 208 | lv_obj_set_style_arc_opa(ui_Arc3, 255, LV_PART_INDICATOR | LV_STATE_DEFAULT); 209 | 210 | lv_obj_set_style_bg_color(ui_Arc3, lv_color_hex(0xD20000), LV_PART_KNOB | LV_STATE_DEFAULT); 211 | lv_obj_set_style_bg_opa(ui_Arc3, 255, LV_PART_KNOB | LV_STATE_DEFAULT); 212 | lv_obj_set_style_pad_left(ui_Arc3, 0, LV_PART_KNOB | LV_STATE_DEFAULT); 213 | lv_obj_set_style_pad_right(ui_Arc3, 0, LV_PART_KNOB | LV_STATE_DEFAULT); 214 | lv_obj_set_style_pad_top(ui_Arc3, 0, LV_PART_KNOB | LV_STATE_DEFAULT); 215 | lv_obj_set_style_pad_bottom(ui_Arc3, 0, LV_PART_KNOB | LV_STATE_DEFAULT); 216 | 217 | ui_Panel7 = lv_obj_create(ui_radar); 218 | lv_obj_set_width(ui_Panel7, 150); 219 | lv_obj_set_height(ui_Panel7, 150); 220 | lv_obj_set_align(ui_Panel7, LV_ALIGN_CENTER); 221 | lv_obj_clear_flag(ui_Panel7, LV_OBJ_FLAG_SCROLLABLE); /// Flags 222 | lv_obj_set_style_radius(ui_Panel7, 360, LV_PART_MAIN | LV_STATE_DEFAULT); 223 | lv_obj_set_style_bg_color(ui_Panel7, lv_color_hex(0x101418), LV_PART_MAIN | LV_STATE_DEFAULT); 224 | lv_obj_set_style_bg_opa(ui_Panel7, 255, LV_PART_MAIN | LV_STATE_DEFAULT); 225 | lv_obj_set_style_border_color(ui_Panel7, lv_color_hex(0x080808), LV_PART_MAIN | LV_STATE_DEFAULT); 226 | lv_obj_set_style_border_opa(ui_Panel7, 255, LV_PART_MAIN | LV_STATE_DEFAULT); 227 | 228 | ui_Distance = lv_label_create(ui_Panel7); 229 | lv_obj_set_width(ui_Distance, LV_SIZE_CONTENT); /// 1 230 | lv_obj_set_height(ui_Distance, LV_SIZE_CONTENT); /// 1 231 | lv_obj_set_align(ui_Distance, LV_ALIGN_CENTER); 232 | lv_label_set_text(ui_Distance, "0.00"); 233 | lv_obj_set_style_text_color(ui_Distance, lv_color_hex(0xC50000), LV_PART_MAIN | LV_STATE_DEFAULT); 234 | lv_obj_set_style_text_opa(ui_Distance, 255, LV_PART_MAIN | LV_STATE_DEFAULT); 235 | lv_obj_set_style_text_align(ui_Distance, LV_TEXT_ALIGN_AUTO, LV_PART_MAIN | LV_STATE_DEFAULT); 236 | lv_obj_set_style_text_decor(ui_Distance, LV_TEXT_DECOR_NONE, LV_PART_MAIN | LV_STATE_DEFAULT); 237 | lv_obj_set_style_text_font(ui_Distance, &ui_font_wise60, LV_PART_MAIN | LV_STATE_DEFAULT); 238 | 239 | ui_MovementType = lv_label_create(ui_radar); 240 | lv_obj_set_width(ui_MovementType, LV_SIZE_CONTENT); /// 1 241 | lv_obj_set_height(ui_MovementType, LV_SIZE_CONTENT); /// 1 242 | lv_obj_set_x(ui_MovementType, 0); 243 | lv_obj_set_y(ui_MovementType, -53); 244 | lv_obj_set_align(ui_MovementType, LV_ALIGN_CENTER); 245 | lv_label_set_text(ui_MovementType, "Movemet"); 246 | lv_obj_set_style_text_color(ui_MovementType, lv_color_hex(0x808080), LV_PART_MAIN | LV_STATE_DEFAULT); 247 | lv_obj_set_style_text_opa(ui_MovementType, 255, LV_PART_MAIN | LV_STATE_DEFAULT); 248 | 249 | } 250 | static void ui_watch_screen_init(void) 251 | { 252 | 253 | 254 | // ui_Panel2 = lv_obj_create(ui_Screen1); 255 | // lv_obj_set_width(ui_Panel2, 220); 256 | // lv_obj_set_height(ui_Panel2, 220); 257 | // lv_obj_set_align(ui_Panel2, LV_ALIGN_CENTER); 258 | // lv_obj_clear_flag(ui_Panel2, LV_OBJ_FLAG_SCROLLABLE); /// Flags 259 | // lv_obj_set_style_radius(ui_Panel2, 360, LV_PART_MAIN | LV_STATE_DEFAULT); 260 | // lv_obj_set_style_bg_color(ui_Panel2, lv_color_hex(0x0E0303), LV_PART_MAIN | LV_STATE_DEFAULT); 261 | // lv_obj_set_style_bg_opa(ui_Panel2, 255, LV_PART_MAIN | LV_STATE_DEFAULT); 262 | // lv_obj_set_style_bg_img_src(ui_Panel2, &ui_img_patern3_png, LV_PART_MAIN | LV_STATE_DEFAULT); 263 | // lv_obj_set_style_bg_img_tiled(ui_Panel2, true, LV_PART_MAIN | LV_STATE_DEFAULT); 264 | // lv_obj_set_style_border_color(ui_Panel2, lv_color_hex(0x101418), LV_PART_MAIN | LV_STATE_DEFAULT); 265 | // lv_obj_set_style_border_opa(ui_Panel2, 255, LV_PART_MAIN | LV_STATE_DEFAULT); 266 | // lv_obj_set_style_border_side(ui_Panel2, LV_BORDER_SIDE_FULL, LV_PART_MAIN | LV_STATE_DEFAULT); 267 | 268 | ui_Panel2 = lv_obj_create(ui_Screen1); 269 | lv_obj_set_width(ui_Panel2, 220); 270 | lv_obj_set_height(ui_Panel2, 220); 271 | lv_obj_set_align(ui_Panel2, LV_ALIGN_CENTER); 272 | lv_obj_clear_flag(ui_Panel2, LV_OBJ_FLAG_SCROLLABLE); /// Flags 273 | lv_obj_set_style_radius(ui_Panel2, 360, LV_PART_MAIN | LV_STATE_DEFAULT); 274 | lv_obj_set_style_bg_color(ui_Panel2, lv_color_hex(0x0E0303), LV_PART_MAIN | LV_STATE_DEFAULT); 275 | lv_obj_set_style_bg_opa(ui_Panel2, 255, LV_PART_MAIN | LV_STATE_DEFAULT); 276 | lv_obj_set_style_bg_img_src(ui_Panel2, &ui_img_1321029331, LV_PART_MAIN | LV_STATE_DEFAULT); 277 | lv_obj_set_style_border_color(ui_Panel2, lv_color_hex(0x101418), LV_PART_MAIN | LV_STATE_DEFAULT); 278 | lv_obj_set_style_border_opa(ui_Panel2, 255, LV_PART_MAIN | LV_STATE_DEFAULT); 279 | lv_obj_set_style_border_side(ui_Panel2, LV_BORDER_SIDE_FULL, LV_PART_MAIN | LV_STATE_DEFAULT); 280 | 281 | 282 | ui_Arc2 = lv_arc_create(ui_Screen1); 283 | lv_obj_set_width(ui_Arc2, 240); 284 | lv_obj_set_height(ui_Arc2, 240); 285 | lv_obj_set_align(ui_Arc2, LV_ALIGN_CENTER); 286 | lv_obj_add_flag(ui_Arc2, LV_OBJ_FLAG_ADV_HITTEST); /// Flags 287 | lv_arc_set_range(ui_Arc2, 0, 100); 288 | lv_arc_set_value(ui_Arc2, 100); 289 | lv_arc_set_bg_angles(ui_Arc2, 0, 360); 290 | lv_arc_set_mode(ui_Arc2, LV_ARC_MODE_NORMAL); 291 | lv_arc_set_rotation(ui_Arc2, 270); 292 | lv_obj_set_style_arc_color(ui_Arc2, lv_color_hex(0x101418), LV_PART_MAIN | LV_STATE_DEFAULT); 293 | lv_obj_set_style_arc_opa(ui_Arc2, 255, LV_PART_MAIN | LV_STATE_DEFAULT); 294 | 295 | lv_obj_set_style_arc_color(ui_Arc2, lv_color_hex(0xD20000), LV_PART_INDICATOR | LV_STATE_DEFAULT); 296 | lv_obj_set_style_arc_opa(ui_Arc2, 255, LV_PART_INDICATOR | LV_STATE_DEFAULT); 297 | 298 | lv_obj_set_style_bg_color(ui_Arc2, lv_color_hex(0xD20000), LV_PART_KNOB | LV_STATE_DEFAULT); 299 | lv_obj_set_style_bg_opa(ui_Arc2, 255, LV_PART_KNOB | LV_STATE_DEFAULT); 300 | lv_obj_set_style_pad_left(ui_Arc2, 0, LV_PART_KNOB | LV_STATE_DEFAULT); 301 | lv_obj_set_style_pad_right(ui_Arc2, 0, LV_PART_KNOB | LV_STATE_DEFAULT); 302 | lv_obj_set_style_pad_top(ui_Arc2, 0, LV_PART_KNOB | LV_STATE_DEFAULT); 303 | lv_obj_set_style_pad_bottom(ui_Arc2, 0, LV_PART_KNOB | LV_STATE_DEFAULT); 304 | // 305 | // ui_Panel2 = lv_obj_create(ui_Screen1); 306 | // lv_obj_set_width(ui_Panel2, 200); 307 | // lv_obj_set_height(ui_Panel2, 200); 308 | // lv_obj_set_align(ui_Panel2, LV_ALIGN_CENTER); 309 | // lv_obj_clear_flag(ui_Panel2, LV_OBJ_FLAG_SCROLLABLE); /// Flags 310 | // lv_obj_set_style_radius(ui_Panel2, 360, LV_PART_MAIN | LV_STATE_DEFAULT); 311 | // lv_obj_set_style_bg_color(ui_Panel2, lv_color_hex(0x0E0303), LV_PART_MAIN | LV_STATE_DEFAULT); 312 | // lv_obj_set_style_bg_opa(ui_Panel2, 255, LV_PART_MAIN | LV_STATE_DEFAULT); 313 | // lv_obj_set_style_border_color(ui_Panel2, lv_color_hex(0x101418), LV_PART_MAIN | LV_STATE_DEFAULT); 314 | // lv_obj_set_style_border_opa(ui_Panel2, 255, LV_PART_MAIN | LV_STATE_DEFAULT); 315 | // lv_obj_set_style_border_side(ui_Panel2, LV_BORDER_SIDE_FULL, LV_PART_MAIN | LV_STATE_DEFAULT); 316 | // 317 | ui_Panel1 = lv_obj_create(ui_Screen1); 318 | lv_obj_set_width(ui_Panel1, 150); 319 | lv_obj_set_height(ui_Panel1, 150); 320 | lv_obj_set_align(ui_Panel1, LV_ALIGN_CENTER); 321 | lv_obj_clear_flag(ui_Panel1, LV_OBJ_FLAG_SCROLLABLE); /// Flags 322 | lv_obj_set_style_radius(ui_Panel1, 360, LV_PART_MAIN | LV_STATE_DEFAULT); 323 | lv_obj_set_style_bg_color(ui_Panel1, lv_color_hex(0x101418), LV_PART_MAIN | LV_STATE_DEFAULT); 324 | lv_obj_set_style_bg_opa(ui_Panel1, 255, LV_PART_MAIN | LV_STATE_DEFAULT); 325 | lv_obj_set_style_border_color(ui_Panel1, lv_color_hex(0x080808), LV_PART_MAIN | LV_STATE_DEFAULT); 326 | lv_obj_set_style_border_opa(ui_Panel1, 255, LV_PART_MAIN | LV_STATE_DEFAULT); 327 | // 328 | ui_Label2 = lv_label_create(ui_Panel1); 329 | lv_obj_set_width(ui_Label2, LV_SIZE_CONTENT); /// 1 330 | lv_obj_set_height(ui_Label2, LV_SIZE_CONTENT); /// 1 331 | lv_obj_set_align(ui_Label2, LV_ALIGN_CENTER); 332 | lv_label_set_text(ui_Label2, "15:10"); 333 | lv_obj_set_style_text_color(ui_Label2, lv_color_hex(0xC50000), LV_PART_MAIN | LV_STATE_DEFAULT); 334 | lv_obj_set_style_text_opa(ui_Label2, 255, LV_PART_MAIN | LV_STATE_DEFAULT); 335 | lv_obj_set_style_text_align(ui_Label2, LV_TEXT_ALIGN_AUTO, LV_PART_MAIN | LV_STATE_DEFAULT); 336 | lv_obj_set_style_text_decor(ui_Label2, LV_TEXT_DECOR_NONE, LV_PART_MAIN | LV_STATE_DEFAULT); 337 | lv_obj_set_style_text_font(ui_Label2, &ui_font_wise60, LV_PART_MAIN | LV_STATE_DEFAULT); 338 | 339 | ui_Label3 = lv_label_create(ui_Screen1); 340 | lv_obj_set_width(ui_Label3, LV_SIZE_CONTENT); /// 1 341 | lv_obj_set_height(ui_Label3, LV_SIZE_CONTENT); /// 1 342 | lv_obj_set_x(ui_Label3, 0); 343 | lv_obj_set_y(ui_Label3, -53); 344 | lv_obj_set_align(ui_Label3, LV_ALIGN_CENTER); 345 | // lv_label_set_text(ui_Label3, "W"); 346 | lv_label_set_text_static(ui_Label3, LV_SYMBOL_WIFI); 347 | lv_obj_set_style_text_color(ui_Label3, lv_color_hex(0x808080), LV_PART_MAIN | LV_STATE_DEFAULT); 348 | lv_obj_set_style_text_opa(ui_Label3, 255, LV_PART_MAIN | LV_STATE_DEFAULT); 349 | 350 | ui_Label4 = lv_label_create(ui_Screen1); 351 | lv_obj_set_width(ui_Label4, LV_SIZE_CONTENT); /// 1 352 | lv_obj_set_height(ui_Label4, LV_SIZE_CONTENT); /// 1 353 | lv_obj_set_x(ui_Label4, 0); 354 | lv_obj_set_y(ui_Label4, 41); 355 | lv_obj_set_align(ui_Label4, LV_ALIGN_CENTER); 356 | lv_label_set_text(ui_Label4, "12 °C"); 357 | lv_obj_set_style_text_color(ui_Label4, lv_color_hex(0xD50000), LV_PART_MAIN | LV_STATE_DEFAULT); 358 | lv_obj_set_style_text_opa(ui_Label4, 255, LV_PART_MAIN | LV_STATE_DEFAULT); 359 | lv_obj_set_style_text_font(ui_Label4, &lv_font_montserrat_20, LV_PART_MAIN | LV_STATE_DEFAULT); 360 | } 361 | 362 | static void ui_lamp_screen_init(void) 363 | { 364 | 365 | //ui_lamp = lv_obj_create(NULL); 366 | lv_obj_clear_flag(ui_lamp, LV_OBJ_FLAG_SCROLLABLE); /// Flags 367 | 368 | ui_Panel9 = lv_obj_create(ui_lamp); 369 | lv_obj_set_width(ui_Panel9, 240); 370 | lv_obj_set_height(ui_Panel9, 240); 371 | lv_obj_set_align(ui_Panel9, LV_ALIGN_CENTER); 372 | lv_obj_clear_flag(ui_Panel9, LV_OBJ_FLAG_SCROLLABLE); /// Flags 373 | lv_obj_set_style_bg_color(ui_Panel9, lv_color_hex(0xFFFFFF), LV_PART_MAIN | LV_STATE_DEFAULT); 374 | lv_obj_set_style_bg_opa(ui_Panel9, 0, LV_PART_MAIN | LV_STATE_DEFAULT); 375 | lv_obj_set_style_bg_img_src(ui_Panel9, &ui_img_bg3_png, LV_PART_MAIN | LV_STATE_DEFAULT); 376 | lv_obj_set_style_border_color(ui_Panel9, lv_color_hex(0x000000), LV_PART_MAIN | LV_STATE_DEFAULT); 377 | lv_obj_set_style_border_opa(ui_Panel9, 0, LV_PART_MAIN | LV_STATE_DEFAULT); 378 | 379 | ui_Switch1 = lv_switch_create(ui_Panel9); 380 | lv_obj_set_width(ui_Switch1, 29); 381 | lv_obj_set_height(ui_Switch1, 13); 382 | lv_obj_set_x(ui_Switch1, -35); 383 | lv_obj_set_y(ui_Switch1, -70); 384 | lv_obj_set_align(ui_Switch1, LV_ALIGN_CENTER); 385 | lv_obj_set_style_bg_color(ui_Switch1, lv_color_hex(0xD30000), LV_PART_MAIN | LV_STATE_CHECKED); 386 | lv_obj_set_style_bg_opa(ui_Switch1, 255, LV_PART_MAIN | LV_STATE_CHECKED); 387 | 388 | lv_obj_set_style_bg_color(ui_Switch1, lv_color_hex(0xFFFFFF), LV_PART_INDICATOR | LV_STATE_CHECKED); 389 | lv_obj_set_style_bg_opa(ui_Switch1, 255, LV_PART_INDICATOR | LV_STATE_CHECKED); 390 | lv_obj_set_style_bg_color(ui_Switch1, lv_color_hex(0xD50000), LV_PART_INDICATOR | LV_STATE_PRESSED); 391 | lv_obj_set_style_bg_opa(ui_Switch1, 255, LV_PART_INDICATOR | LV_STATE_PRESSED); 392 | 393 | lv_obj_set_style_bg_color(ui_Switch1, lv_color_hex(0xD50000), LV_PART_KNOB | LV_STATE_DEFAULT); 394 | lv_obj_set_style_bg_opa(ui_Switch1, 255, LV_PART_KNOB | LV_STATE_DEFAULT); 395 | lv_obj_set_style_bg_color(ui_Switch1, lv_color_hex(0x293031), LV_PART_KNOB | LV_STATE_PRESSED); 396 | lv_obj_set_style_bg_opa(ui_Switch1, 255, LV_PART_KNOB | LV_STATE_PRESSED); 397 | 398 | ui_Switch3 = lv_switch_create(ui_Panel9); 399 | lv_obj_set_width(ui_Switch3, 29); 400 | lv_obj_set_height(ui_Switch3, 13); 401 | lv_obj_set_x(ui_Switch3, 35); 402 | lv_obj_set_y(ui_Switch3, -70); 403 | lv_obj_set_align(ui_Switch3, LV_ALIGN_CENTER); 404 | lv_obj_set_style_bg_color(ui_Switch3, lv_color_hex(0xD30000), LV_PART_MAIN | LV_STATE_CHECKED); 405 | lv_obj_set_style_bg_opa(ui_Switch3, 255, LV_PART_MAIN | LV_STATE_CHECKED); 406 | 407 | lv_obj_set_style_bg_color(ui_Switch3, lv_color_hex(0xFFFFFF), LV_PART_INDICATOR | LV_STATE_CHECKED); 408 | lv_obj_set_style_bg_opa(ui_Switch3, 255, LV_PART_INDICATOR | LV_STATE_CHECKED); 409 | lv_obj_set_style_bg_color(ui_Switch3, lv_color_hex(0xD50000), LV_PART_INDICATOR | LV_STATE_PRESSED); 410 | lv_obj_set_style_bg_opa(ui_Switch3, 255, LV_PART_INDICATOR | LV_STATE_PRESSED); 411 | 412 | lv_obj_set_style_bg_color(ui_Switch3, lv_color_hex(0xD50000), LV_PART_KNOB | LV_STATE_DEFAULT); 413 | lv_obj_set_style_bg_opa(ui_Switch3, 255, LV_PART_KNOB | LV_STATE_DEFAULT); 414 | lv_obj_set_style_bg_color(ui_Switch3, lv_color_hex(0x293031), LV_PART_KNOB | LV_STATE_PRESSED); 415 | lv_obj_set_style_bg_opa(ui_Switch3, 255, LV_PART_KNOB | LV_STATE_PRESSED); 416 | 417 | ui_Colorwheel2 = lv_colorwheel_create(ui_Panel9, true); 418 | lv_obj_set_width(ui_Colorwheel2, 240); 419 | lv_obj_set_height(ui_Colorwheel2, 240); 420 | lv_obj_set_align(ui_Colorwheel2, LV_ALIGN_CENTER); 421 | 422 | ui_Label4 = lv_label_create(ui_Panel9); 423 | lv_obj_set_width(ui_Label4, LV_SIZE_CONTENT); /// 1 424 | lv_obj_set_height(ui_Label4, LV_SIZE_CONTENT); /// 1 425 | lv_obj_set_x(ui_Label4, 35); 426 | lv_obj_set_y(ui_Label4, -85); 427 | lv_obj_set_align(ui_Label4, LV_ALIGN_CENTER); 428 | lv_label_set_text(ui_Label4, "W"); 429 | lv_obj_set_style_text_color(ui_Label4, lv_color_hex(0xD50000), LV_PART_MAIN | LV_STATE_DEFAULT); 430 | lv_obj_set_style_text_opa(ui_Label4, 255, LV_PART_MAIN | LV_STATE_DEFAULT); 431 | 432 | ui_Label6 = lv_label_create(ui_Panel9); 433 | lv_obj_set_width(ui_Label6, LV_SIZE_CONTENT); /// 1 434 | lv_obj_set_height(ui_Label6, LV_SIZE_CONTENT); /// 1 435 | lv_obj_set_x(ui_Label6, -35); 436 | lv_obj_set_y(ui_Label6, -85); 437 | lv_obj_set_align(ui_Label6, LV_ALIGN_CENTER); 438 | lv_label_set_text(ui_Label6, "MQTT"); 439 | lv_obj_set_style_text_color(ui_Label6, lv_color_hex(0xD50000), LV_PART_MAIN | LV_STATE_DEFAULT); 440 | lv_obj_set_style_text_opa(ui_Label6, 255, LV_PART_MAIN | LV_STATE_DEFAULT); 441 | 442 | ui_Panel10 = lv_obj_create(ui_lamp); 443 | lv_obj_set_width(ui_Panel10, 150); 444 | lv_obj_set_height(ui_Panel10, 150); 445 | lv_obj_set_align(ui_Panel10, LV_ALIGN_CENTER); 446 | lv_obj_clear_flag(ui_Panel10, LV_OBJ_FLAG_SCROLLABLE); /// Flags 447 | lv_obj_set_style_bg_color(ui_Panel10, lv_color_hex(0xFFFFFF), LV_PART_MAIN | LV_STATE_DEFAULT); 448 | lv_obj_set_style_bg_opa(ui_Panel10, 0, LV_PART_MAIN | LV_STATE_DEFAULT); 449 | lv_obj_set_style_border_color(ui_Panel10, lv_color_hex(0x000000), LV_PART_MAIN | LV_STATE_DEFAULT); 450 | lv_obj_set_style_border_opa(ui_Panel10, 0, LV_PART_MAIN | LV_STATE_DEFAULT); 451 | 452 | ui_Image8 = lv_img_create(ui_Panel10); 453 | lv_img_set_src(ui_Image8, &ui_img_off_bulb_png); 454 | lv_obj_set_width(ui_Image8, LV_SIZE_CONTENT); /// 1 455 | lv_obj_set_height(ui_Image8, LV_SIZE_CONTENT); /// 1 456 | lv_obj_set_align(ui_Image8, LV_ALIGN_CENTER); 457 | lv_obj_add_flag(ui_Image8, LV_OBJ_FLAG_ADV_HITTEST); /// Flags 458 | lv_obj_clear_flag(ui_Image8, LV_OBJ_FLAG_SCROLLABLE); /// Flags 459 | lv_img_set_zoom(ui_Image8, 400); 460 | 461 | ui_Image9 = lv_img_create(ui_Panel10); 462 | lv_img_set_src(ui_Image9, &ui_img_bulb_png); 463 | lv_obj_set_width(ui_Image9, LV_SIZE_CONTENT); /// 1 464 | lv_obj_set_height(ui_Image9, LV_SIZE_CONTENT); /// 1 465 | lv_obj_set_align(ui_Image9, LV_ALIGN_CENTER); 466 | lv_obj_add_flag(ui_Image9, LV_OBJ_FLAG_HIDDEN | LV_OBJ_FLAG_ADV_HITTEST); /// Flags 467 | lv_obj_clear_flag(ui_Image9, LV_OBJ_FLAG_SCROLLABLE); /// Flags 468 | lv_img_set_zoom(ui_Image9, 400); 469 | 470 | } 471 | 472 | -------------------------------------------------------------------------------- /main/display/lvgl_demo_ui.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * USEFUL ELECTRONICS 4 | ******************************************************************************/ 5 | /** 6 | ****************************************************************************** 7 | * @file : lvgl_demo_ui.h 8 | * @author : WARD ALMASARANI 9 | * @version : v.1.0 10 | * @date : Feb 1, 2023 11 | * @link : https://www.youtube.com/@usefulelectronics 12 | * Hold Ctrl button and click on the link to be directed to 13 | Useful Electronics YouTube channel 14 | ******************************************************************************/ 15 | 16 | #ifndef MAIN_LVGL_DEMO_UI_H_ 17 | #define MAIN_LVGL_DEMO_UI_H_ 18 | 19 | 20 | /* INCLUDES ------------------------------------------------------------------*/ 21 | #include "lvgl.h" 22 | 23 | /* MACROS --------------------------------------------------------------------*/ 24 | 25 | /* ENUMORATIONS --------------------------------------------------------------*/ 26 | 27 | /* STRUCTURES & TYPEDEFS -----------------------------------------------------*/ 28 | typedef union 29 | { 30 | char time[6]; 31 | struct 32 | { 33 | uint16_t hour; 34 | uint8_t semi; 35 | uint16_t minute; 36 | uint8_t reserved; 37 | }sel; 38 | }watch_t; 39 | /* VARIABLES -----------------------------------------------------------------*/ 40 | extern lv_obj_t * ui_Screen1; 41 | extern lv_obj_t * ui_Arc2; 42 | extern lv_obj_t * ui_Panel2; 43 | extern lv_obj_t * ui_Panel1; 44 | extern lv_obj_t * ui_Label2; 45 | extern lv_obj_t * ui_Label3; 46 | extern lv_obj_t * ui_Label4; 47 | 48 | //Radar Screen 49 | extern lv_obj_t * ui_radar; 50 | extern lv_obj_t * ui_Panel6; 51 | extern lv_obj_t * ui_Arc3; 52 | extern lv_obj_t * ui_Panel7; 53 | extern lv_obj_t * ui_Distance; 54 | extern lv_obj_t * ui_MovementType; 55 | 56 | extern watch_t realTime; 57 | 58 | 59 | 60 | 61 | LV_FONT_DECLARE(ui_font_wise60); 62 | LV_FONT_DECLARE(lv_font_montserrat_20); 63 | 64 | LV_IMG_DECLARE(ui_img_1321029331); 65 | 66 | LV_IMG_DECLARE(ui_img_off_bulb_png); 67 | LV_IMG_DECLARE(ui_img_bulb_png); 68 | LV_IMG_DECLARE(ui_img_bg3_png); 69 | //LV_IMG_DECLARE(ui_img_patern3_png); 70 | 71 | 72 | /* FUNCTIONS DECLARATION -----------------------------------------------------*/ 73 | void set_value(int32_t v, bool buttonStatus); 74 | void ui_set_wheel_color(lv_color_hsv_t* hsv); 75 | void ui_set_wheel_mode(lv_colorwheel_mode_t mode); 76 | void ui_set_mqtt_switch_state(bool state); 77 | void ui_set_wifi_switch_state(bool state); 78 | void ui_set_lamp_state(bool state); 79 | void ui_init(void); 80 | 81 | 82 | 83 | #endif /* MAIN_LVGL_DEMO_UI_H_ */ 84 | 85 | /*************************************** USEFUL ELECTRONICS*****END OF FILE****/ 86 | -------------------------------------------------------------------------------- /main/display/ui_helpers.c: -------------------------------------------------------------------------------- 1 | // SquareLine LVGL GENERATED FILE 2 | // EDITOR VERSION: SquareLine Studio 1.2.0 3 | // LVGL VERSION: 8.3.4 4 | // PROJECT: SquareLine_Project 5 | 6 | #include "ui_helpers.h" 7 | 8 | 9 | void _ui_bar_set_property(lv_obj_t * target, int id, int val) 10 | { 11 | if(id == _UI_BAR_PROPERTY_VALUE_WITH_ANIM) lv_bar_set_value(target, val, LV_ANIM_ON); 12 | if(id == _UI_BAR_PROPERTY_VALUE) lv_bar_set_value(target, val, LV_ANIM_OFF); 13 | } 14 | 15 | void _ui_basic_set_property(lv_obj_t * target, int id, int val) 16 | { 17 | if(id == _UI_BASIC_PROPERTY_POSITION_X) lv_obj_set_x(target, val); 18 | if(id == _UI_BASIC_PROPERTY_POSITION_Y) lv_obj_set_y(target, val); 19 | if(id == _UI_BASIC_PROPERTY_WIDTH) lv_obj_set_width(target, val); 20 | if(id == _UI_BASIC_PROPERTY_HEIGHT) lv_obj_set_height(target, val); 21 | } 22 | 23 | 24 | void _ui_dropdown_set_property(lv_obj_t * target, int id, int val) 25 | { 26 | if(id == _UI_DROPDOWN_PROPERTY_SELECTED) lv_dropdown_set_selected(target, val); 27 | } 28 | 29 | void _ui_image_set_property(lv_obj_t * target, int id, uint8_t * val) 30 | { 31 | if(id == _UI_IMAGE_PROPERTY_IMAGE) lv_img_set_src(target, val); 32 | } 33 | 34 | void _ui_label_set_property(lv_obj_t * target, int id, char * val) 35 | { 36 | if(id == _UI_LABEL_PROPERTY_TEXT) lv_label_set_text(target, val); 37 | } 38 | 39 | 40 | void _ui_roller_set_property(lv_obj_t * target, int id, int val) 41 | { 42 | if(id == _UI_ROLLER_PROPERTY_SELECTED_WITH_ANIM) lv_roller_set_selected(target, val, LV_ANIM_ON); 43 | if(id == _UI_ROLLER_PROPERTY_SELECTED) lv_roller_set_selected(target, val, LV_ANIM_OFF); 44 | } 45 | 46 | void _ui_slider_set_property(lv_obj_t * target, int id, int val) 47 | { 48 | if(id == _UI_SLIDER_PROPERTY_VALUE_WITH_ANIM) lv_slider_set_value(target, val, LV_ANIM_ON); 49 | if(id == _UI_SLIDER_PROPERTY_VALUE) lv_slider_set_value(target, val, LV_ANIM_OFF); 50 | } 51 | 52 | 53 | void _ui_screen_change(lv_obj_t * target, lv_scr_load_anim_t fademode, int spd, int delay) 54 | { 55 | lv_scr_load_anim(target, fademode, spd, delay, false); 56 | } 57 | 58 | /** 59 | * @brief handle the data to be viewed in the radar UI page 60 | * 61 | */ 62 | void _ui_radar(uint8_t movement_type, uint16_t detected_distance) 63 | { 64 | char distance_string[10] = {0}; 65 | uint8_t meter = 0; 66 | uint8_t cm = 0; 67 | 68 | char movement_type_string[10] = {0}; 69 | 70 | meter = detected_distance / 100; 71 | 72 | cm = detected_distance % 100; 73 | 74 | sprintf(distance_string, "%d.%02d", meter, cm); 75 | 76 | if(movement_type) 77 | { 78 | sprintf(movement_type_string, "MOVEMENT"); 79 | } 80 | else 81 | { 82 | sprintf(movement_type_string, "STATIC"); 83 | } 84 | 85 | lv_label_set_text(ui_Distance, distance_string); 86 | lv_label_set_text(ui_MovementType, movement_type_string); 87 | lv_arc_set_value(ui_Arc3, _ui_arc_scale_radar(detected_distance)); 88 | 89 | } 90 | /** 91 | * @brief Scale the value read from the rader and scale it to the screen arc 92 | * 93 | * @param Value_to_scale : read value to scale 94 | * 95 | * @return scaled value 96 | */ 97 | uint16_t _ui_arc_scale_radar(uint16_t Value_to_scale) 98 | { 99 | const uint16_t max_from = 1000; 100 | 101 | const uint16_t max_to = 180; 102 | 103 | return (Value_to_scale * max_to )/ max_from; 104 | } 105 | /** 106 | * @brief Seconds circle handler function 107 | * 108 | */ 109 | void _ui_arc_increment() 110 | { 111 | static uint16_t counter = 0; 112 | static bool direction = true; 113 | static char timeString[6] = {0}; 114 | 115 | memcpy(timeString, &realTime.sel.hour,2); 116 | timeString[2] = realTime.sel.semi; 117 | memcpy(timeString + 3, &realTime.sel.minute,2); 118 | 119 | switch (direction) 120 | { 121 | case true: 122 | ++counter; 123 | break; 124 | case false: 125 | --counter; 126 | break; 127 | } 128 | 129 | if(0 == counter) 130 | { 131 | direction = true; 132 | _ui_arc_reverse(); 133 | realTime.sel.semi = ':'; 134 | lv_label_set_text(ui_Label2, timeString); 135 | // lv_label_set_text(ui_Label2, "15:10"); 136 | } 137 | else if(100 == counter) 138 | { 139 | direction = false; 140 | _ui_arc_reverse(); 141 | realTime.sel.semi = '.'; 142 | 143 | lv_label_set_text(ui_Label2, timeString); 144 | } 145 | 146 | // int old = lv_arc_get_value(ui_Arc2); 147 | lv_arc_set_value(ui_Arc2, counter); 148 | // lv_event_send(ui_Arc2, LV_EVENT_VALUE_CHANGED, 0); 149 | } 150 | void _ui_arc_set(int val) 151 | { 152 | lv_arc_set_value(ui_Arc2, val); 153 | } 154 | void _ui_arc_reverse() 155 | { 156 | static bool mode = false; 157 | 158 | if(mode) 159 | { 160 | lv_arc_set_mode(ui_Arc2, LV_ARC_MODE_NORMAL); 161 | } 162 | else 163 | { 164 | lv_arc_set_mode(ui_Arc2, LV_ARC_MODE_REVERSE); 165 | 166 | } 167 | 168 | //toggle mode 169 | mode ^= true; 170 | } 171 | 172 | void _ui_temp_set(char* tempString) 173 | { 174 | lv_label_set_text(ui_Label4, tempString); 175 | } 176 | 177 | 178 | void _ui_text_wifiIndicate(bool connectionStatus) 179 | { 180 | switch (connectionStatus) 181 | { 182 | case true: 183 | lv_obj_set_style_text_color(ui_Label3, lv_color_hex(0xD20000), LV_PART_MAIN | LV_STATE_DEFAULT); 184 | break; 185 | case false: 186 | lv_obj_set_style_text_color(ui_Label3, lv_color_hex(0x808080), LV_PART_MAIN | LV_STATE_DEFAULT); 187 | break; 188 | default: 189 | break; 190 | } 191 | 192 | } 193 | void _ui_bar_increment(lv_obj_t * target, int val, int anm) 194 | { 195 | int old = lv_bar_get_value(target); 196 | lv_bar_set_value(target, old + val, anm); 197 | } 198 | 199 | void _ui_slider_increment(lv_obj_t * target, int val, int anm) 200 | { 201 | int old = lv_slider_get_value(target); 202 | lv_slider_set_value(target, old + val, anm); 203 | lv_event_send(target, LV_EVENT_VALUE_CHANGED, 0); 204 | } 205 | 206 | void _ui_keyboard_set_target(lv_obj_t * keyboard, lv_obj_t * textarea) 207 | { 208 | lv_keyboard_set_textarea(keyboard, textarea); 209 | } 210 | 211 | void _ui_flag_modify(lv_obj_t * target, int32_t flag, int value) 212 | { 213 | if(value == _UI_MODIFY_FLAG_TOGGLE) { 214 | if(lv_obj_has_flag(target, flag)) lv_obj_clear_flag(target, flag); 215 | else lv_obj_add_flag(target, flag); 216 | } 217 | else if(value == _UI_MODIFY_FLAG_ADD) lv_obj_add_flag(target, flag); 218 | else lv_obj_clear_flag(target, flag); 219 | } 220 | void _ui_state_modify(lv_obj_t * target, int32_t state, int value) 221 | { 222 | if(value == _UI_MODIFY_STATE_TOGGLE) { 223 | if(lv_obj_has_state(target, state)) lv_obj_clear_state(target, state); 224 | else lv_obj_add_state(target, state); 225 | } 226 | else if(value == _UI_MODIFY_STATE_ADD) lv_obj_add_state(target, state); 227 | else lv_obj_clear_state(target, state); 228 | } 229 | 230 | void _ui_opacity_set(lv_obj_t * target, int val) 231 | { 232 | lv_obj_set_style_opa(target, val, 0); 233 | } 234 | 235 | void _ui_anim_callback_set_x(lv_anim_t * a, int32_t v) 236 | { 237 | lv_obj_set_x((lv_obj_t *)a->user_data, v); 238 | } 239 | 240 | void _ui_anim_callback_set_y(lv_anim_t * a, int32_t v) 241 | { 242 | lv_obj_set_y((lv_obj_t *)a->user_data, v); 243 | } 244 | 245 | void _ui_anim_callback_set_width(lv_anim_t * a, int32_t v) 246 | { 247 | lv_obj_set_width((lv_obj_t *)a->user_data, v); 248 | } 249 | 250 | void _ui_anim_callback_set_height(lv_anim_t * a, int32_t v) 251 | { 252 | lv_obj_set_height((lv_obj_t *)a->user_data, v); 253 | } 254 | 255 | void _ui_anim_callback_set_opacity(lv_anim_t * a, int32_t v) 256 | { 257 | lv_obj_set_style_opa((lv_obj_t *)a->user_data, v, 0); 258 | } 259 | 260 | void _ui_anim_callback_set_image_zoom(lv_anim_t * a, int32_t v) 261 | { 262 | lv_img_set_zoom((lv_obj_t *)a->user_data, v); 263 | } 264 | 265 | void _ui_anim_callback_set_image_angle(lv_anim_t * a, int32_t v) 266 | { 267 | lv_img_set_angle((lv_obj_t *)a->user_data, v); 268 | } 269 | 270 | 271 | int32_t _ui_anim_callback_get_x(lv_anim_t * a) 272 | { 273 | return lv_obj_get_x_aligned((lv_obj_t *)a->user_data); 274 | } 275 | 276 | int32_t _ui_anim_callback_get_y(lv_anim_t * a) 277 | { 278 | return lv_obj_get_y_aligned((lv_obj_t *)a->user_data); 279 | } 280 | 281 | int32_t _ui_anim_callback_get_width(lv_anim_t * a) 282 | { 283 | return lv_obj_get_width((lv_obj_t *)a->user_data); 284 | } 285 | 286 | int32_t _ui_anim_callback_get_height(lv_anim_t * a) 287 | { 288 | return lv_obj_get_height((lv_obj_t *)a->user_data); 289 | } 290 | 291 | int32_t _ui_anim_callback_get_opacity(lv_anim_t * a) 292 | { 293 | return lv_obj_get_style_opa((lv_obj_t *)a->user_data, 0); 294 | } 295 | 296 | int32_t _ui_anim_callback_get_image_zoom(lv_anim_t * a) 297 | { 298 | return lv_img_get_zoom((lv_obj_t *)a->user_data); 299 | } 300 | 301 | int32_t _ui_anim_callback_get_image_angle(lv_anim_t * a) 302 | { 303 | return lv_img_get_angle((lv_obj_t *)a->user_data); 304 | } 305 | 306 | void _ui_arc_set_text_value(lv_obj_t * trg, lv_obj_t * src, char * prefix, char * postfix) 307 | { 308 | char buf[_UI_TEMPORARY_STRING_BUFFER_SIZE]; 309 | lv_snprintf(buf, sizeof(buf), "%s%d%s", prefix, (int)lv_arc_get_value(src), postfix); 310 | lv_label_set_text(trg, buf); 311 | } 312 | 313 | void _ui_slider_set_text_value(lv_obj_t * trg, lv_obj_t * src, char * prefix, char * postfix) 314 | { 315 | char buf[_UI_TEMPORARY_STRING_BUFFER_SIZE]; 316 | lv_snprintf(buf, sizeof(buf), "%s%d%s", prefix, (int)lv_slider_get_value(src), postfix); 317 | lv_label_set_text(trg, buf); 318 | } 319 | void _ui_checked_set_text_value(lv_obj_t * trg, lv_obj_t * src, char * txt_on, char * txt_off) 320 | { 321 | if(lv_obj_has_state(src, LV_STATE_CHECKED)) lv_label_set_text(trg, txt_on); 322 | else lv_label_set_text(trg, txt_off); 323 | } 324 | 325 | 326 | -------------------------------------------------------------------------------- /main/display/ui_helpers.h: -------------------------------------------------------------------------------- 1 | // SquareLine LVGL GENERATED FILE 2 | // EDITOR VERSION: SquareLine Studio 1.2.0 3 | // LVGL VERSION: 8.3.4 4 | // PROJECT: SquareLine_Project 5 | 6 | #ifndef _SQUARELINE_PROJECT_UI_HELPERS_H 7 | #define _SQUARELINE_PROJECT_UI_HELPERS_H 8 | 9 | #include "lvgl_demo_ui.h" 10 | #include 11 | 12 | #define _UI_TEMPORARY_STRING_BUFFER_SIZE 32 13 | #define _UI_BAR_PROPERTY_VALUE 0 14 | #define _UI_BAR_PROPERTY_VALUE_WITH_ANIM 1 15 | void _ui_bar_set_property(lv_obj_t * target, int id, int val); 16 | 17 | #define _UI_BASIC_PROPERTY_POSITION_X 0 18 | #define _UI_BASIC_PROPERTY_POSITION_Y 1 19 | #define _UI_BASIC_PROPERTY_WIDTH 2 20 | #define _UI_BASIC_PROPERTY_HEIGHT 3 21 | void _ui_basic_set_property(lv_obj_t * target, int id, int val); 22 | 23 | #define _UI_DROPDOWN_PROPERTY_SELECTED 0 24 | void _ui_dropdown_set_property(lv_obj_t * target, int id, int val); 25 | 26 | #define _UI_IMAGE_PROPERTY_IMAGE 0 27 | void _ui_image_set_property(lv_obj_t * target, int id, uint8_t * val); 28 | 29 | #define _UI_LABEL_PROPERTY_TEXT 0 30 | void _ui_label_set_property(lv_obj_t * target, int id, char * val); 31 | 32 | #define _UI_ROLLER_PROPERTY_SELECTED 0 33 | #define _UI_ROLLER_PROPERTY_SELECTED_WITH_ANIM 1 34 | void _ui_roller_set_property(lv_obj_t * target, int id, int val); 35 | 36 | #define _UI_SLIDER_PROPERTY_VALUE 0 37 | #define _UI_SLIDER_PROPERTY_VALUE_WITH_ANIM 1 38 | void _ui_slider_set_property(lv_obj_t * target, int id, int val); 39 | 40 | void _ui_screen_change(lv_obj_t * target, lv_scr_load_anim_t fademode, int spd, int delay); 41 | 42 | void _ui_radar(uint8_t movement_type, uint16_t detected_distance); 43 | uint16_t _ui_arc_scale_radar(uint16_t Value_to_scale); 44 | 45 | void _ui_arc_increment(); 46 | void _ui_arc_reverse(); 47 | void _ui_arc_set(int val); 48 | void _ui_temp_set(char* tempString); 49 | 50 | void _ui_text_wifiIndicate(bool connectionStatus); 51 | 52 | void _ui_bar_increment(lv_obj_t * target, int val, int anm); 53 | 54 | void _ui_slider_increment(lv_obj_t * target, int val, int anm); 55 | 56 | void _ui_keyboard_set_target(lv_obj_t * keyboard, lv_obj_t * textarea); 57 | 58 | #define _UI_MODIFY_FLAG_ADD 0 59 | #define _UI_MODIFY_FLAG_REMOVE 1 60 | #define _UI_MODIFY_FLAG_TOGGLE 2 61 | void _ui_flag_modify(lv_obj_t * target, int32_t flag, int value); 62 | 63 | #define _UI_MODIFY_STATE_ADD 0 64 | #define _UI_MODIFY_STATE_REMOVE 1 65 | #define _UI_MODIFY_STATE_TOGGLE 2 66 | void _ui_state_modify(lv_obj_t * target, int32_t state, int value); 67 | 68 | void _ui_opacity_set(lv_obj_t * target, int val); 69 | 70 | void _ui_anim_callback_set_x(lv_anim_t * a, int32_t v); 71 | 72 | void _ui_anim_callback_set_y(lv_anim_t * a, int32_t v); 73 | 74 | void _ui_anim_callback_set_width(lv_anim_t * a, int32_t v); 75 | 76 | void _ui_anim_callback_set_height(lv_anim_t * a, int32_t v); 77 | 78 | void _ui_anim_callback_set_opacity(lv_anim_t * a, int32_t v); 79 | 80 | void _ui_anim_callback_set_image_zoom(lv_anim_t * a, int32_t v); 81 | 82 | void _ui_anim_callback_set_image_angle(lv_anim_t * a, int32_t v); 83 | 84 | int32_t _ui_anim_callback_get_x(lv_anim_t * a); 85 | 86 | int32_t _ui_anim_callback_get_y(lv_anim_t * a); 87 | 88 | int32_t _ui_anim_callback_get_width(lv_anim_t * a); 89 | 90 | int32_t _ui_anim_callback_get_height(lv_anim_t * a); 91 | 92 | int32_t _ui_anim_callback_get_opacity(lv_anim_t * a); 93 | 94 | int32_t _ui_anim_callback_get_image_zoom(lv_anim_t * a); 95 | 96 | int32_t _ui_anim_callback_get_image_angle(lv_anim_t * a); 97 | 98 | void _ui_arc_set_text_value(lv_obj_t * trg, lv_obj_t * src, char * prefix, char * postfix); 99 | 100 | void _ui_slider_set_text_value(lv_obj_t * trg, lv_obj_t * src, char * prefix, char * postfix); 101 | 102 | void _ui_checked_set_text_value(lv_obj_t * trg, lv_obj_t * src, char * txt_on, char * txt_off); 103 | 104 | 105 | #endif 106 | -------------------------------------------------------------------------------- /main/display/ui_img_patern3_png.c: -------------------------------------------------------------------------------- 1 | // SquareLine LVGL GENERATED FILE 2 | // EDITOR VERSION: SquareLine Studio 1.2.1 3 | // LVGL VERSION: 8.3.4 4 | // PROJECT: SquareLine_Project 5 | 6 | #include "lvgl_demo_ui.h" 7 | 8 | #ifndef LV_ATTRIBUTE_MEM_ALIGN 9 | #define LV_ATTRIBUTE_MEM_ALIGN 10 | #endif 11 | 12 | // IMAGE DATA: assets\patern3.png 13 | const LV_ATTRIBUTE_MEM_ALIGN uint8_t ui_img_patern3_png_data[] = { 14 | 0x63, 0x0C, 0xFF, 0x42, 0x08, 0xFF, 0x21, 0x24, 0xFF, 0x18, 0xE3, 0xFF, 0x18, 0xC3, 0xFF, 0x10, 0xA2, 0xFF, 0x10, 0xA2, 0xFF, 0x18, 0xE3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x10, 0xA2, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xE3, 0xFF, 0x10, 0xA2, 0xFF, 0x10, 0x82, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x10, 0xA2, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x10, 0xA2, 0xFF, 0x10, 0xA2, 0xFF, 0x18, 0xE3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x21, 0x24, 0xFF, 0x42, 0x08, 0xFF, 0x63, 0x0C, 0xFF, 0x6B, 0x6D, 0xFF, 0x7B, 0xEF, 0xFF, 0x6B, 0x6D, 0xFF, 0x42, 0x08, 0xFF, 0x18, 0xE3, 0xFF, 0x18, 0xE3, 0xFF, 0x18, 0xE3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xE3, 0xFF, 0x18, 0xC3, 0xFF, 0x10, 0xA2, 0xFF, 0x18, 0xE3, 0xFF, 0x21, 0x04, 0xFF, 0x10, 0xA2, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 15 | 0x10, 0xA2, 0xFF, 0x10, 0xA2, 0xFF, 0x21, 0x04, 0xFF, 0x21, 0x04, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xE3, 0xFF, 0x18, 0xE3, 0xFF, 0x10, 0x82, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xE3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x42, 0x08, 0xFF, 0x73, 0x8E, 0xFF, 0x7B, 0xEF, 0xFF, 0x6B, 0x4D, 0xFF, 0x7B, 0xCF, 0xFF, 0x6B, 0x4D, 0xFF, 0x6B, 0x6D, 0xFF, 0x7B, 0xEF, 0xFF, 0x6B, 0x4D, 0xFF, 0x31, 0xA6, 0xFF, 0x10, 0xA2, 0xFF, 0x10, 0xA2, 0xFF, 0x18, 0xE3, 0xFF, 0x10, 0x82, 0xFF, 0x08, 0x61, 0xFF, 0x18, 0xC3, 0xFF, 0x21, 0x04, 0xFF, 0x10, 0xA2, 0xFF, 0x10, 0x82, 0xFF, 0x18, 0xE3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xE3, 0xFF, 0x18, 0xC3, 0xFF, 0x10, 0x82, 0xFF, 0x10, 0xA2, 0xFF, 0x18, 0xE3, 0xFF, 0x08, 0x61, 0xFF, 0x08, 0x61, 0xFF, 0x29, 0x45, 0xFF, 0x10, 0xA2, 0xFF, 0x10, 0xA2, 0xFF, 0x31, 0xA6, 0xFF, 0x63, 0x2C, 0xFF, 0x7B, 0xEF, 0xFF, 0x73, 0x8E, 0xFF, 0x6B, 0x6D, 0xFF, 0x7B, 0xCF, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0xAE, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0xAE, 0xFF, 0x7B, 0xCF, 0xFF, 0x5A, 0xEB, 0xFF, 0x31, 0x86, 0xFF, 16 | 0x10, 0x82, 0xFF, 0x21, 0x24, 0xFF, 0x21, 0x04, 0xFF, 0x10, 0x82, 0xFF, 0x10, 0x82, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x10, 0xA2, 0xFF, 0x18, 0xC3, 0xFF, 0x10, 0xA2, 0xFF, 0x08, 0x61, 0xFF, 0x18, 0xE3, 0xFF, 0x21, 0x24, 0xFF, 0x08, 0x61, 0xFF, 0x29, 0x65, 0xFF, 0x5A, 0xEB, 0xFF, 0x7B, 0xEF, 0xFF, 0x73, 0xAE, 0xFF, 0x6B, 0x4D, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x7B, 0xCF, 0xFF, 0x73, 0xAE, 0xFF, 0x6B, 0x6D, 0xFF, 0x6B, 0x6D, 0xFF, 0x7B, 0xCF, 0xFF, 0x52, 0xAA, 0xFF, 0x21, 0x04, 0xFF, 0x10, 0xA2, 0xFF, 0x21, 0x04, 0xFF, 0x10, 0xA2, 0xFF, 0x10, 0xA2, 0xFF, 0x21, 0x04, 0xFF, 0x10, 0xA2, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xE3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x21, 0x04, 0xFF, 0x10, 0xA2, 0xFF, 0x21, 0x04, 0xFF, 0x52, 0x8A, 0xFF, 17 | 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x7B, 0xCF, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0x8E, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0x8E, 0xFF, 0x39, 0xE7, 0xFF, 0x10, 0xA2, 0xFF, 0x21, 0x24, 0xFF, 0x21, 0x04, 0xFF, 0x08, 0x61, 0xFF, 0x10, 0xA2, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x10, 0xA2, 0xFF, 0x10, 0xA2, 0xFF, 0x18, 0xE3, 0xFF, 0x18, 0xC3, 0xFF, 0x10, 0xA2, 0xFF, 0x39, 0xE7, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0x8E, 0xFF, 0x7B, 0xCF, 0xFF, 0x7B, 0xCF, 0xFF, 0x73, 0x8E, 0xFF, 0x6B, 0x4D, 0xFF, 0x7B, 0xCF, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0xAE, 0xFF, 0x7B, 0xEF, 0xFF, 0x7B, 0xCF, 0xFF, 0x6B, 0x6D, 0xFF, 0x7B, 0xEF, 0xFF, 0x6B, 0x4D, 0xFF, 0x73, 0xAE, 0xFF, 0x6B, 0x6D, 0xFF, 0x29, 0x65, 0xFF, 0x10, 0x82, 0xFF, 0x18, 0xE3, 0xFF, 0x18, 0xE3, 0xFF, 18 | 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xE3, 0xFF, 0x10, 0xA2, 0xFF, 0x10, 0xA2, 0xFF, 0x39, 0xC7, 0xFF, 0x6B, 0x4D, 0xFF, 0x7B, 0xCF, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x7B, 0xCF, 0xFF, 0x7B, 0xCF, 0xFF, 0x73, 0x8E, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0xAE, 0xFF, 0x7B, 0xCF, 0xFF, 0x7B, 0xCF, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x5A, 0xCB, 0xFF, 0x29, 0x45, 0xFF, 0x10, 0x82, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x10, 0xA2, 0xFF, 0x31, 0x86, 0xFF, 0x5A, 0xCB, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 19 | 0x6B, 0x6D, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x6B, 0x6D, 0xFF, 0x7B, 0xEF, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x4A, 0x69, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x10, 0xA2, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x10, 0xA2, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x4A, 0x69, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x6B, 0x6D, 0xFF, 0x6B, 0x6D, 0xFF, 0x84, 0x10, 0xFF, 0x6B, 0x4D, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x7B, 0xCF, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x6B, 0x4D, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x6B, 0x6D, 0xFF, 0x4A, 0x69, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xE3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xE3, 0xFF, 0x18, 0xC3, 0xFF, 0x4A, 0x69, 0xFF, 20 | 0x6B, 0x6D, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0xAE, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x7B, 0xCF, 0xFF, 0x6B, 0x4D, 0xFF, 0x63, 0x2C, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x10, 0xA2, 0xFF, 0x42, 0x08, 0xFF, 0x6B, 0x4D, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0xAE, 0xFF, 0x7B, 0xCF, 0xFF, 0x73, 0xAE, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x7B, 0xCF, 0xFF, 0x73, 0xAE, 0xFF, 0x29, 0x45, 0xFF, 0x18, 0xE3, 0xFF, 0x10, 0xA2, 0xFF, 0x10, 0xA2, 0xFF, 0x18, 0xE3, 0xFF, 0x29, 0x45, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0xAE, 0xFF, 0x7B, 0xCF, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0xAE, 0xFF, 0x63, 0x2C, 0xFF, 0x42, 0x08, 0xFF, 0x10, 0xA2, 0xFF, 0x10, 0xA2, 0xFF, 0x10, 0x82, 0xFF, 0x21, 0x04, 0xFF, 0x4A, 0x49, 0xFF, 0x6B, 0x4D, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x7B, 0xCF, 0xFF, 21 | 0x73, 0xAE, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x4A, 0x49, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x4A, 0x49, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0xAE, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x6B, 0x6D, 0xFF, 0x4A, 0x49, 0xFF, 0x18, 0xE3, 0xFF, 0x08, 0x61, 0xFF, 0x18, 0xC3, 0xFF, 0x21, 0x04, 0xFF, 0x21, 0x04, 0xFF, 0x10, 0xA2, 0xFF, 0x10, 0x82, 0xFF, 0x29, 0x45, 0xFF, 0x52, 0xAA, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0xAE, 0xFF, 0x7B, 0xCF, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x63, 0x0C, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x63, 0x0C, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x7B, 0xCF, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 22 | 0x73, 0xAE, 0xFF, 0x6B, 0x6D, 0xFF, 0x52, 0x8A, 0xFF, 0x21, 0x24, 0xFF, 0x10, 0x82, 0xFF, 0x18, 0xC3, 0xFF, 0x21, 0x04, 0xFF, 0x18, 0xE3, 0xFF, 0x10, 0x82, 0xFF, 0x10, 0xA2, 0xFF, 0x18, 0xE3, 0xFF, 0x21, 0x04, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x31, 0xA6, 0xFF, 0x5A, 0xEB, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0xAE, 0xFF, 0x5A, 0xEB, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x5A, 0xEB, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x5A, 0xEB, 0xFF, 0x31, 0xA6, 0xFF, 0x10, 0xA2, 0xFF, 0x10, 0xA2, 0xFF, 0x21, 0x04, 0xFF, 0x18, 0xE3, 0xFF, 0x10, 0xA2, 0xFF, 0x10, 0x82, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xE3, 0xFF, 0x18, 0xE3, 0xFF, 0x10, 0xA2, 0xFF, 0x10, 0x82, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xE3, 0xFF, 0x18, 0xC3, 0xFF, 0x52, 0x8A, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 23 | 0x73, 0xAE, 0xFF, 0x5A, 0xCB, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x5A, 0xCB, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x6B, 0x6D, 0xFF, 0x6B, 0x4D, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x52, 0x8A, 0xFF, 0x10, 0xA2, 0xFF, 0x18, 0xE3, 0xFF, 0x18, 0xE3, 0xFF, 0x10, 0x82, 0xFF, 0x10, 0x82, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xE3, 0xFF, 0x18, 0xE3, 0xFF, 0x18, 0xC3, 0xFF, 0x10, 0xA2, 0xFF, 0x10, 0xA2, 0xFF, 0x18, 0xC3, 0xFF, 0x21, 0x04, 0xFF, 0x18, 0xE3, 0xFF, 0x18, 0xC3, 0xFF, 0x10, 0xA2, 0xFF, 0x21, 0x04, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x7B, 0xEF, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0x8E, 0xFF, 0x63, 0x0C, 0xFF, 0x10, 0xA2, 0xFF, 0x18, 0xE3, 0xFF, 0x18, 0xE3, 0xFF, 0x10, 0xA2, 0xFF, 0x63, 0x0C, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x7B, 0xCF, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0xAE, 0xFF, 0x6B, 0x6D, 0xFF, 0x21, 0x04, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xE3, 0xFF, 0x18, 0xE3, 0xFF, 0x18, 0xC3, 0xFF, 0x10, 0xA2, 0xFF, 0x18, 0xC3, 0xFF, 24 | 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x5A, 0xEB, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x5A, 0xEB, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x5A, 0xEB, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x5A, 0xEB, 0xFF, 0x73, 0x8E, 0xFF, 25 | 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x5A, 0xEB, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x5A, 0xEB, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 26 | 0x18, 0xC3, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x5A, 0xEB, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x5A, 0xEB, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x5A, 0xEB, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x5A, 0xEB, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x18, 0xC3, 0xFF, 27 | 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x5A, 0xEB, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x5A, 0xEB, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 28 | 0x73, 0x8E, 0xFF, 0x5A, 0xEB, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x5A, 0xEB, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x5A, 0xEB, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x5A, 0xEB, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 29 | 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x10, 0xA2, 0xFF, 0x10, 0xA2, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xE3, 0xFF, 0x18, 0xC3, 0xFF, 0x10, 0xA2, 0xFF, 0x21, 0x04, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x7B, 0xCF, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0x8E, 0xFF, 0x63, 0x2C, 0xFF, 0x10, 0xA2, 0xFF, 0x18, 0xE3, 0xFF, 0x18, 0xE3, 0xFF, 0x10, 0xA2, 0xFF, 0x63, 0x2C, 0xFF, 0x73, 0x8E, 0xFF, 0x6B, 0x6D, 0xFF, 0x7B, 0xEF, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x6B, 0x4D, 0xFF, 0x21, 0x04, 0xFF, 0x10, 0xA2, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xE3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x10, 0xA2, 0xFF, 0x18, 0xE3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x10, 0xA2, 0xFF, 0x10, 0xA2, 0xFF, 0x10, 0x82, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xE3, 0xFF, 0x4A, 0x69, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x5A, 0xCB, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x5A, 0xCB, 0xFF, 0x73, 0xAE, 0xFF, 30 | 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0xAE, 0xFF, 0x4A, 0x69, 0xFF, 0x18, 0xE3, 0xFF, 0x10, 0xA2, 0xFF, 0x10, 0x82, 0xFF, 0x10, 0xA2, 0xFF, 0x10, 0xA2, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xE3, 0xFF, 0x10, 0x82, 0xFF, 0x10, 0xA2, 0xFF, 0x18, 0xE3, 0xFF, 0x21, 0x04, 0xFF, 0x10, 0xA2, 0xFF, 0x18, 0xC3, 0xFF, 0x39, 0xC7, 0xFF, 0x5A, 0xEB, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x5A, 0xEB, 0xFF, 0x18, 0xE3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xE3, 0xFF, 0x5A, 0xEB, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x6B, 0x6D, 0xFF, 0x5A, 0xCB, 0xFF, 0x39, 0xC7, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xE3, 0xFF, 0x18, 0xC3, 0xFF, 0x10, 0xA2, 0xFF, 0x10, 0xA2, 0xFF, 0x18, 0xC3, 0xFF, 0x21, 0x04, 0xFF, 0x18, 0xC3, 0xFF, 0x08, 0x61, 0xFF, 0x21, 0x24, 0xFF, 0x5A, 0xCB, 0xFF, 0x73, 0xAE, 0xFF, 0x6B, 0x6D, 0xFF, 31 | 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0x8E, 0xFF, 0x7B, 0xCF, 0xFF, 0x73, 0xAE, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0x8E, 0xFF, 0x63, 0x0C, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x63, 0x0C, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x7B, 0xCF, 0xFF, 0x73, 0xAE, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0x8E, 0xFF, 0x5A, 0xCB, 0xFF, 0x21, 0x24, 0xFF, 0x08, 0x61, 0xFF, 0x18, 0xC3, 0xFF, 0x21, 0x04, 0xFF, 0x18, 0xE3, 0xFF, 0x18, 0xC3, 0xFF, 0x08, 0x61, 0xFF, 0x18, 0xE3, 0xFF, 0x52, 0x8A, 0xFF, 0x6B, 0x6D, 0xFF, 0x6B, 0x6D, 0xFF, 0x6B, 0x6D, 0xFF, 0x7B, 0xCF, 0xFF, 0x73, 0xAE, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0xAE, 0xFF, 0x4A, 0x49, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x4A, 0x49, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0xAE, 0xFF, 32 | 0x7B, 0xEF, 0xFF, 0x6B, 0x6D, 0xFF, 0x6B, 0x6D, 0xFF, 0x6B, 0x6D, 0xFF, 0x52, 0x8A, 0xFF, 0x21, 0x04, 0xFF, 0x08, 0x61, 0xFF, 0x18, 0xC3, 0xFF, 0x10, 0xA2, 0xFF, 0x39, 0xE7, 0xFF, 0x6B, 0x4D, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0xAE, 0xFF, 0x7B, 0xCF, 0xFF, 0x73, 0xAE, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0xAE, 0xFF, 0x6B, 0x6D, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0xAE, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0xAE, 0xFF, 0x29, 0x45, 0xFF, 0x18, 0xE3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xE3, 0xFF, 0x29, 0x45, 0xFF, 0x73, 0xAE, 0xFF, 0x7B, 0xCF, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0xAE, 0xFF, 0x6B, 0x4D, 0xFF, 0x42, 0x08, 0xFF, 0x10, 0xA2, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0xAE, 0xFF, 0x6B, 0x6D, 0xFF, 0x6B, 0x6D, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0xAE, 0xFF, 0x7B, 0xCF, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x6B, 0x6D, 0xFF, 33 | 0x4A, 0x69, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xE3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xE3, 0xFF, 0x18, 0xC3, 0xFF, 0x4A, 0x69, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0xAE, 0xFF, 0x6B, 0x4D, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x6B, 0x6D, 0xFF, 0x6B, 0x6D, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x6B, 0x6D, 0xFF, 0x84, 0x10, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x52, 0x8A, 0xFF, 0x18, 0xE3, 0xFF, 0x18, 0xC3, 0xFF, 0x10, 0xA2, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x10, 0xA2, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xE3, 0xFF, 0x4A, 0x69, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x7B, 0xEF, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 34 | 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x5A, 0xCB, 0xFF, 0x31, 0x86, 0xFF, 0x10, 0x82, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x10, 0xA2, 0xFF, 0x29, 0x65, 0xFF, 0x52, 0xAA, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0xAE, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x7B, 0xCF, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x7B, 0xCF, 0xFF, 0x73, 0xAE, 0xFF, 0x6B, 0x6D, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0x8E, 0xFF, 0x7B, 0xCF, 0xFF, 0x73, 0xAE, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x7B, 0xCF, 0xFF, 0x6B, 0x4D, 0xFF, 0x39, 0xC7, 0xFF, 0x10, 0xA2, 0xFF, 0x10, 0xA2, 0xFF, 0x18, 0xE3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 35 | 0x18, 0xC3, 0xFF, 0x10, 0xA2, 0xFF, 0x18, 0xC3, 0xFF, 0x31, 0xA6, 0xFF, 0x6B, 0x4D, 0xFF, 0x7B, 0xCF, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0xAE, 0xFF, 0x7B, 0xCF, 0xFF, 0x73, 0xAE, 0xFF, 0x6B, 0x6D, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0xAE, 0xFF, 0x7B, 0xCF, 0xFF, 0x6B, 0x4D, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x6B, 0x4D, 0xFF, 0x39, 0xE7, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xE3, 0xFF, 0x10, 0xA2, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x10, 0xA2, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xE3, 0xFF, 0x10, 0xA2, 0xFF, 0x10, 0xA2, 0xFF, 0x42, 0x08, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x7B, 0xCF, 0xFF, 0x7B, 0xCF, 0xFF, 0x73, 0x8E, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x7B, 0xCF, 0xFF, 0x73, 0xAE, 0xFF, 0x6B, 0x6D, 0xFF, 0x6B, 0x6D, 0xFF, 0x7B, 0xCF, 0xFF, 36 | 0x52, 0x8A, 0xFF, 0x21, 0x24, 0xFF, 0x10, 0xA2, 0xFF, 0x21, 0x04, 0xFF, 0x18, 0xC3, 0xFF, 0x10, 0xA2, 0xFF, 0x18, 0xE3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x10, 0xA2, 0xFF, 0x18, 0xE3, 0xFF, 0x21, 0x04, 0xFF, 0x10, 0x82, 0xFF, 0x21, 0x04, 0xFF, 0x52, 0x8A, 0xFF, 0x7B, 0xCF, 0xFF, 0x6B, 0x6D, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0xAE, 0xFF, 0x7B, 0xCF, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0xAE, 0xFF, 0x73, 0xAE, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0xAE, 0xFF, 0x7B, 0xCF, 0xFF, 0x5A, 0xCB, 0xFF, 0x31, 0x86, 0xFF, 0x08, 0x61, 0xFF, 0x21, 0x24, 0xFF, 0x21, 0x04, 0xFF, 0x10, 0x82, 0xFF, 0x10, 0xA2, 0xFF, 0x18, 0xC3, 0xFF, 0x10, 0xA2, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xE3, 0xFF, 0x10, 0x82, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x10, 0x82, 0xFF, 0x18, 0xE3, 0xFF, 0x21, 0x04, 0xFF, 0x08, 0x61, 0xFF, 37 | 0x31, 0x86, 0xFF, 0x5A, 0xCB, 0xFF, 0x7B, 0xCF, 0xFF, 0x73, 0x8E, 0xFF, 0x6B, 0x6D, 0xFF, 0x73, 0x8E, 0xFF, 0x73, 0xAE, 0xFF, 0x6B, 0x6D, 0xFF, 0x7B, 0xEF, 0xFF, 0x6B, 0x6D, 0xFF, 0x6B, 0x6D, 0xFF, 0x7B, 0xEF, 0xFF, 0x6B, 0x4D, 0xFF, 0x31, 0xA6, 0xFF, 0x10, 0xA2, 0xFF, 0x10, 0xA2, 0xFF, 0x21, 0x24, 0xFF, 0x08, 0x61, 0xFF, 0x08, 0x61, 0xFF, 0x18, 0xE3, 0xFF, 0x10, 0xA2, 0xFF, 0x10, 0x82, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xE3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xE3, 0xFF, 0x10, 0xA2, 0xFF, 0x10, 0xA2, 0xFF, 0x18, 0xC3, 0xFF, 0x10, 0x82, 0xFF, 0x10, 0x82, 0xFF, 0x21, 0x24, 0xFF, 0x10, 0xA2, 0xFF, 0x10, 0xA2, 0xFF, 0x31, 0xA6, 0xFF, 0x6B, 0x4D, 0xFF, 0x7B, 0xEF, 0xFF, 0x6B, 0x6D, 0xFF, 0x6B, 0x4D, 0xFF, 0x7B, 0xCF, 0xFF, 0x73, 0x8E, 0xFF, 0x7B, 0xEF, 0xFF, 0x73, 0x8E, 0xFF, 0x42, 0x08, 0xFF, 0x18, 0xE3, 0xFF, 0x18, 0xE3, 0xFF, 0x21, 0x04, 0xFF, 0x18, 0xC3, 0xFF, 0x10, 0x82, 0xFF, 0x18, 0xE3, 0xFF, 0x18, 0xE3, 0xFF, 0x18, 0xC3, 0xFF, 0x21, 0x04, 0xFF, 0x21, 0x04, 0xFF, 0x18, 0xC3, 0xFF, 0x10, 0xA2, 0xFF, 38 | 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x10, 0x82, 0xFF, 0x18, 0xC3, 0xFF, 0x21, 0x04, 0xFF, 0x18, 0xE3, 0xFF, 0x10, 0xA2, 0xFF, 0x18, 0xE3, 0xFF, 0x21, 0x04, 0xFF, 0x10, 0x82, 0xFF, 0x18, 0xC3, 0xFF, 0x21, 0x04, 0xFF, 0x18, 0xE3, 0xFF, 0x18, 0xE3, 0xFF, 0x42, 0x08, 0xFF, 0x73, 0x8E, 0xFF, 0x7B, 0xEF, 0xFF, 0x6B, 0x6D, 0xFF, 0x5A, 0xEB, 0xFF, 0x42, 0x08, 0xFF, 0x21, 0x24, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x10, 0xA2, 0xFF, 0x10, 0xA2, 0xFF, 0x18, 0xE3, 0xFF, 0x18, 0xE3, 0xFF, 0x10, 0xA2, 0xFF, 0x10, 0xA2, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x10, 0xA2, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xE3, 0xFF, 0x10, 0xA2, 0xFF, 0x10, 0xA2, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xE3, 0xFF, 0x10, 0x82, 0xFF, 0x10, 0x82, 0xFF, 0x18, 0xE3, 0xFF, 0x18, 0xC3, 0xFF, 0x10, 0xA2, 0xFF, 0x10, 0xA2, 0xFF, 0x18, 0xC3, 0xFF, 0x18, 0xC3, 0xFF, 0x21, 0x24, 0xFF, 0x42, 0x08, 0xFF, 0x5A, 0xEB, 0xFF, 39 | }; 40 | const lv_img_dsc_t ui_img_patern3_png = { 41 | .header.always_zero = 0, 42 | .header.w = 40, 43 | .header.h = 40, 44 | .data_size = sizeof(ui_img_patern3_png_data), 45 | .header.cf = LV_IMG_CF_TRUE_COLOR_ALPHA, 46 | .data = ui_img_patern3_png_data 47 | }; 48 | 49 | -------------------------------------------------------------------------------- /main/display/ui_page.c: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * USEFUL ELECTRONICS 4 | ******************************************************************************/ 5 | /** 6 | ****************************************************************************** 7 | * @file : ui_page.c 8 | * @author : WARD ALMASARANI 9 | * @version : v.1.0 10 | * @date : Nov 19, 2024 11 | * @link : https://www.youtube.com/@usefulelectronics 12 | * Hold Ctrl button and click on the link to be directed to 13 | Useful Electronics YouTube channel 14 | ******************************************************************************/ 15 | 16 | 17 | /* INCLUDES ------------------------------------------------------------------*/ 18 | #include "ui_page.h" 19 | /* MACROS --------------------------------------------------------------------*/ 20 | #define UI_OPTION_WATCH_TITLE "Time" 21 | #define UI_OPTION_MEASURE_TITLE "Measure" 22 | #define UI_OPTION_TEMPERATURE_TITLE "Temperature" 23 | #define UI_OPTION_WEATHER_TITLE "Weather" 24 | /* PRIVATE STRUCTRES ---------------------------------------------------------*/ 25 | 26 | /* VARIABLES -----------------------------------------------------------------*/ 27 | ui_option_t option_watch = 28 | { 29 | .title = UI_OPTION_WATCH_TITLE, 30 | .actions = &(ui_action_t){.forward = NULL, .back = NULL, .idle = NULL }, 31 | .next_option = &option_measure, 32 | .sub_option = NULL, 33 | .icon = NULL, 34 | }; 35 | 36 | ui_option_t option_measure = 37 | { 38 | .title = UI_OPTION_MEASURE_TITLE, 39 | .actions = &(ui_action_t){.forward = NULL, .back = NULL, .idle = NULL }, 40 | .next_option = &option_temperature, 41 | .sub_option = NULL, 42 | .icon = NULL, 43 | }; 44 | 45 | ui_option_t option_temperature = 46 | { 47 | .title = UI_OPTION_TEMPERATURE_TITLE, 48 | .actions = &(ui_action_t){.forward = NULL, .back = NULL, .idle = NULL }, 49 | .next_option = &option_weather, 50 | .sub_option = NULL, 51 | .icon = NULL, 52 | }; 53 | 54 | ui_option_t option_weather = 55 | { 56 | .title = UI_OPTION_WEATHER_TITLE, 57 | .actions = &(ui_action_t){.forward = NULL, .back = NULL, .idle = NULL }, 58 | .next_option = &option_lamp1, 59 | .sub_option = NULL, 60 | .icon = NULL, 61 | }; 62 | 63 | ui_option_t option_lamp1 = 64 | { 65 | .title = "Lamp1", 66 | .actions = &(ui_action_t){.forward = NULL, .back = NULL, .idle = NULL }, 67 | .next_option = &option_lamp2, 68 | .sub_option = NULL, 69 | .icon = NULL, 70 | }; 71 | 72 | ui_option_t option_lamp2 = 73 | { 74 | .title = "Lamp2", 75 | .actions = &(ui_action_t){.forward = NULL, .back = NULL, .idle = NULL }, 76 | .next_option = NULL, 77 | .sub_option = NULL, 78 | .icon = NULL, 79 | }; 80 | /* DEFINITIONS ---------------------------------------------------------------*/ 81 | 82 | /* MACROS --------------------------------------------------------------------*/ 83 | 84 | /* PRIVATE FUNCTIONS DECLARATION ---------------------------------------------*/ 85 | 86 | /* FUNCTION PROTOTYPES -------------------------------------------------------*/ 87 | //ui_option_t *ui_page_option_get(uint8_t option_index) 88 | //{ 89 | 90 | //} 91 | 92 | /*************************************** USEFUL ELECTRONICS*****END OF FILE****/ 93 | -------------------------------------------------------------------------------- /main/display/ui_page.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * USEFUL ELECTRONICS 4 | ******************************************************************************/ 5 | /** 6 | ****************************************************************************** 7 | * @file : ui_page.h 8 | * @author : WARD ALMASARANI 9 | * @version : v.1.0 10 | * @date : Nov 19, 2024 11 | * @link : https://www.youtube.com/@usefulelectronics 12 | * Hold Ctrl button and click on the link to be directed to 13 | Useful Electronics YouTube channel 14 | ******************************************************************************/ 15 | 16 | #ifndef UI_PAGE_H_ 17 | #define UI_PAGE_H_ 18 | 19 | 20 | /* INCLUDES ------------------------------------------------------------------*/ 21 | #include 22 | /* MACROS --------------------------------------------------------------------*/ 23 | #define OPTION_BUFFER_SIZE 30 24 | /* ENUMORATIONS --------------------------------------------------------------*/ 25 | enum 26 | { 27 | UI_PAGE_OPTION_WATCH = 0, 28 | UI_PAGE_OPTION_MEASURE, 29 | UI_PAGE_OPTION_TEMPERATURE, 30 | UI_PAGE_OPTION_WEATHER, 31 | UI_PAGE_OPTION_LAMP1, 32 | UI_PAGE_OPTION_LAMP2, 33 | }; 34 | /* STRUCTURES & TYPEDEFS -----------------------------------------------------*/ 35 | typedef struct action 36 | { 37 | void (*forward)(); 38 | void (*back)(); 39 | void (*idle)(); 40 | }ui_action_t; 41 | 42 | typedef struct option 43 | { 44 | char *title; 45 | struct option *sub_option; 46 | struct option *next_option; 47 | ui_action_t *actions; 48 | uint8_t buffer[OPTION_BUFFER_SIZE]; 49 | void *icon; 50 | uint8_t reserved : 8; 51 | 52 | }ui_option_t; 53 | /* VARIABLES -----------------------------------------------------------------*/ 54 | ui_option_t option_watch; 55 | ui_option_t option_measure; 56 | ui_option_t option_temperature; 57 | ui_option_t option_weather; 58 | ui_option_t option_lamp1; 59 | ui_option_t option_lamp2; 60 | /* FUNCTIONS DECLARATION -----------------------------------------------------*/ 61 | 62 | 63 | 64 | #endif /* UI_PAGE_H_ */ 65 | 66 | /*************************************** USEFUL ELECTRONICS*****END OF FILE****/ 67 | -------------------------------------------------------------------------------- /main/esp_interrupt.c: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * USEFUL ELECTRONICS 4 | ******************************************************************************/ 5 | /** 6 | ****************************************************************************** 7 | * @file : esp_interrupt.c 8 | * @author : WARD ALMASARANI 9 | * @version : v.1.0 10 | * @date : Aug 1, 2023 11 | * @link : https://www.youtube.com/@usefulelectronics 12 | * Hold Ctrl button and click on the link to be directed to 13 | Useful Electronics YouTube channel 14 | ******************************************************************************/ 15 | 16 | 17 | /* INCLUDES ------------------------------------------------------------------*/ 18 | #include "esp_interrupt.h" 19 | 20 | /* PRIVATE STRUCTRES ---------------------------------------------------------*/ 21 | 22 | /* VARIABLES -----------------------------------------------------------------*/ 23 | SemaphoreHandle_t button_sem = NULL; 24 | interrupt_e interrupt_id = IDLE_INT; 25 | static const char* TAG = "interrupt"; 26 | /* DEFINITIONS ---------------------------------------------------------------*/ 27 | 28 | /* MACROS --------------------------------------------------------------------*/ 29 | 30 | /* PRIVATE FUNCTIONS DECLARATION ---------------------------------------------*/ 31 | 32 | /* FUNCTION PROTOTYPES -------------------------------------------------------*/ 33 | /** 34 | * @brief GPIO interrupt service routine will be executed when the related interrupt is fired. this function will give 35 | * button_sem as semaphore and clear the related interrupt flags 36 | * 37 | * @param arg : pointer to the GPIO pin responsible for the interrupt. 38 | */ 39 | void gpio_isr_handle(void *arg) 40 | { 41 | static BaseType_t xHigherPriorityTaskWoken = pdFALSE; 42 | 43 | uint8_t gpio_idx = (uint8_t) arg; 44 | 45 | interrupt_id = EXT_GPIO_INT; 46 | //Notify callback handling task and pass callbackID 47 | xTaskNotifyFromISR( hMain_eventTask, //Task handler to pass the notification to 48 | interrupt_id, //CallbackID to be passed to the function 49 | eSetValueWithOverwrite, //CallbackID will be cleared once the corresponding task is executed 50 | &xHigherPriorityTaskWoken); //After noticing callback handle task, it will be executed immediately 51 | //regardless of its priority in the system. 52 | 53 | //Give priority to callback handling task to handle the callback immediately. 54 | portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); 55 | } 56 | 57 | /*************************************** USEFUL ELECTRONICS*****END OF FILE****/ 58 | -------------------------------------------------------------------------------- /main/esp_interrupt.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * USEFUL ELECTRONICS 4 | ******************************************************************************/ 5 | /** 6 | ****************************************************************************** 7 | * @file : esp_interrupt.h 8 | * @author : WARD ALMASARANI 9 | * @version : v.1.0 10 | * @date : Aug 1, 2023 11 | * @link : https://www.youtube.com/@usefulelectronics 12 | * Hold Ctrl button and click on the link to be directed to 13 | Useful Electronics YouTube channel 14 | ******************************************************************************/ 15 | 16 | #ifndef MAIN_ESP_INTERRUPT_H_ 17 | #define MAIN_ESP_INTERRUPT_H_ 18 | 19 | 20 | /* INCLUDES ------------------------------------------------------------------*/ 21 | #include "driver/gpio.h" 22 | #include "driver/periph_ctrl.h" 23 | #include "esp_log.h" 24 | #include "main.h" 25 | 26 | #include "freertos/FreeRTOS.h" 27 | #include "freertos/task.h" 28 | #include "freertos/queue.h" 29 | #include "freertos/semphr.h" 30 | /* MACROS --------------------------------------------------------------------*/ 31 | 32 | /* ENUMORATIONS --------------------------------------------------------------*/ 33 | 34 | /* STRUCTURES & TYPEDEFS -----------------------------------------------------*/ 35 | typedef enum 36 | { 37 | IDLE_INT = 0, 38 | EXT_GPIO_INT, 39 | }interrupt_e; 40 | /* VARIABLES -----------------------------------------------------------------*/ 41 | extern interrupt_e interrupt_id; 42 | /* FUNCTIONS DECLARATION -----------------------------------------------------*/ 43 | /** 44 | * @brief GPIO interrupt service routine will be executed when the related interrupt is fired. this function will give 45 | * button_sem as semaphore and clear the related interrupt flags 46 | * 47 | * @param arg : pointer to the GPIO pin responsible for the interrupt. 48 | */ 49 | void gpio_isr_handle(void *arg); 50 | 51 | 52 | #endif /* MAIN_ESP_INTERRUPT_H_ */ 53 | 54 | /*************************************** USEFUL ELECTRONICS*****END OF FILE****/ 55 | -------------------------------------------------------------------------------- /main/gpio/gpio_config.c: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * USEFUL ELECTRONICS 4 | ******************************************************************************/ 5 | /** 6 | ****************************************************************************** 7 | * @file : gpio_config.c 8 | * @author : WARD ALMASARANI 9 | * @version : v.1.0 10 | * @date : Jul 30, 2023 11 | * @link : https://www.youtube.com/@usefulelectronics 12 | * Hold Ctrl button and click on the link to be directed to 13 | Useful Electronics YouTube channel 14 | ******************************************************************************/ 15 | 16 | 17 | /* INCLUDES ------------------------------------------------------------------*/ 18 | #include "gpio_config.h" 19 | 20 | /* PRIVATE STRUCTRES ---------------------------------------------------------*/ 21 | 22 | /* VARIABLES -----------------------------------------------------------------*/ 23 | 24 | /* DEFINITIONS ---------------------------------------------------------------*/ 25 | 26 | /* MACROS --------------------------------------------------------------------*/ 27 | 28 | /* PRIVATE FUNCTIONS DECLARATION ---------------------------------------------*/ 29 | 30 | /* FUNCTION PROTOTYPES -------------------------------------------------------*/ 31 | /** 32 | * @brief Configures an external interrupt for a specific GPIO pin. 33 | * 34 | * This function configures an external interrupt for a specific GPIO pin 35 | * on the ESP32 microcontroller. 36 | * 37 | * @param gpio_pin The GPIO pin number to configure for the external interrupt. 38 | * 39 | * @param interrupt_type The type of interrupt triggering (rising edge, falling edge, etc.). 40 | * 41 | * @param gpio_isr_function A pointer to the user-defined ISR (Interrupt Service Routine) function 42 | * that will be called when the interrupt is triggered. 43 | * 44 | */ 45 | void gpio_config_ext_interrupt(uint8_t gpio_pin, gpio_int_type_t interrupt_type, void* gpio_isr_function) 46 | { 47 | gpio_config_t gpio_handler = {0}; 48 | 49 | gpio_handler.intr_type = interrupt_type; 50 | 51 | gpio_handler.mode = GPIO_MODE_INPUT; 52 | 53 | gpio_handler.pin_bit_mask = 1 << gpio_pin; 54 | 55 | gpio_handler.pull_down_en = GPIO_PULLDOWN_DISABLE; 56 | 57 | gpio_handler.pull_up_en = GPIO_PULLUP_DISABLE; 58 | 59 | gpio_config(&gpio_handler); 60 | 61 | gpio_install_isr_service(ESP_INTR_FLAG_LEVEL2); 62 | 63 | gpio_isr_handler_add(gpio_pin, gpio_isr_function, (void*) gpio_pin); 64 | } 65 | /** 66 | * @brief Configures a GPIO pin as output and sets its initial level to LOW. 67 | * 68 | * @param gpio_pin The GPIO pin number to configure as output. 69 | */ 70 | void gpio_config_output(uint8_t gpio_pin) 71 | { 72 | gpio_pad_select_gpio(gpio_pin); 73 | 74 | gpio_set_direction(gpio_pin, GPIO_MODE_OUTPUT); 75 | 76 | gpio_set_level(gpio_pin, GPIO_RESET); 77 | } 78 | /** 79 | * @brief Configures a GPIO pin as input. 80 | * 81 | * @param gpio_pin The GPIO pin number to configure as input. 82 | */ 83 | void gpio_config_input(uint8_t gpio_pin) 84 | { 85 | gpio_pad_select_gpio(gpio_pin); 86 | 87 | gpio_set_direction(gpio_pin, GPIO_MODE_INPUT); 88 | 89 | } 90 | 91 | /*************************************** USEFUL ELECTRONICS*****END OF FILE****/ 92 | -------------------------------------------------------------------------------- /main/gpio/gpio_config.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * USEFUL ELECTRONICS 4 | ******************************************************************************/ 5 | /** 6 | ****************************************************************************** 7 | * @file : gpio_config.h 8 | * @author : WARD ALMASARANI 9 | * @version : v.1.0 10 | * @date : Jul 30, 2023 11 | * @link : https://www.youtube.com/@usefulelectronics 12 | * Hold Ctrl button and click on the link to be directed to 13 | Useful Electronics YouTube channel 14 | ******************************************************************************/ 15 | 16 | #ifndef MAIN_GPIO_CONFIG_H_ 17 | #define MAIN_GPIO_CONFIG_H_ 18 | 19 | 20 | /* INCLUDES ------------------------------------------------------------------*/ 21 | #include "driver/gpio.h" 22 | #include "rom/gpio.h" 23 | /* MACROS --------------------------------------------------------------------*/ 24 | #define GPIO_RESET 0 25 | #define GPIO_SET 1 26 | 27 | #define ENABLE 1 28 | #define DISABLE 0 29 | /* ENUMORATIONS --------------------------------------------------------------*/ 30 | 31 | /* STRUCTURES & TYPEDEFS -----------------------------------------------------*/ 32 | 33 | /* VARIABLES -----------------------------------------------------------------*/ 34 | 35 | /* FUNCTIONS DECLARATION -----------------------------------------------------*/ 36 | 37 | /** 38 | * @brief Configures a GPIO pin as output and sets its initial level to LOW. 39 | * 40 | * @param gpio_pin The GPIO pin number to configure as output. 41 | */ 42 | /** 43 | * @brief Configures an external interrupt for a specific GPIO pin. 44 | * 45 | * This function configures an external interrupt for a specific GPIO pin 46 | * on the ESP32 microcontroller. 47 | * 48 | * @param gpio_pin The GPIO pin number to configure for the external interrupt. 49 | * 50 | * @param interrupt_type The type of interrupt triggering (rising edge, falling edge, etc.). 51 | * 52 | * @param gpio_isr_function A pointer to the user-defined ISR (Interrupt Service Routine) function 53 | * that will be called when the interrupt is triggered. 54 | * 55 | */ 56 | void gpio_config_ext_interrupt(uint8_t gpio_pin, gpio_int_type_t interrupt_type, void* gpio_isr_function); 57 | /** 58 | * @brief Configures a GPIO pin as output and sets its initial level to LOW. 59 | * 60 | * @param gpio_pin The GPIO pin number to configure as output. 61 | */ 62 | void gpio_config_output(uint8_t gpio_pin); 63 | /** 64 | * @brief Configures a GPIO pin as input. 65 | * 66 | * @param gpio_pin The GPIO pin number to configure as input. 67 | */ 68 | void gpio_config_input(uint8_t gpio_pin); 69 | 70 | #endif /* MAIN_GPIO_CONFIG_H_ */ 71 | 72 | /*************************************** USEFUL ELECTRONICS*****END OF FILE****/ 73 | -------------------------------------------------------------------------------- /main/hardware/button.c: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * USEFUL ELECTRONICS 4 | ******************************************************************************/ 5 | /** 6 | ****************************************************************************** 7 | * @file : button.c 8 | * @author : WARD ALMASARANI 9 | * @version : v.1.0 10 | * @date : Jul 30, 2023 11 | * @link : https://www.youtube.com/@usefulelectronics 12 | * Hold Ctrl button and click on the link to be directed to 13 | Useful Electronics YouTube channel 14 | ******************************************************************************/ 15 | 16 | 17 | /* INCLUDES ------------------------------------------------------------------*/ 18 | #include "button.h" 19 | #include "esp_log.h" 20 | /* PRIVATE STRUCTRES ---------------------------------------------------------*/ 21 | // Button configuration structure 22 | typedef struct 23 | { 24 | uint8_t pin; // GPIO pin number for the button 25 | uint8_t pull_type; // pull type either pull up = 1 or pull down = 0 26 | uint32_t long_press_time_ms; // Long press duration in milliseconds 27 | } button_config_t; 28 | 29 | // Button object structure 30 | typedef struct 31 | { 32 | button_config_t config; // Button configuration 33 | button_state_t state; // Current button state 34 | uint32_t press_time; // Timestamp when the button was pressed 35 | bool long_press; // Flag indicating if the button is being long-pressed 36 | uint8_t (*input_read)(void); 37 | void (*callback)(void); 38 | } button_t; 39 | 40 | // Button handler structure 41 | typedef struct 42 | { 43 | uint32_t (*tick)(void); 44 | uint8_t (*input_read)(uint8_t gpio_pin); 45 | } button_handler_t; 46 | /* VARIABLES -----------------------------------------------------------------*/ 47 | //Offset state is used to handle undefined button situation 48 | button_t hw_buttons[HARDWARE_BUTTON_COUNT + HARDWARE_BUTTON_OFFSET] = {0}; 49 | 50 | button_handler_t hButton = {0}; 51 | 52 | uint32_t* (button_tick)(void); 53 | 54 | static uint8_t button_index = 0; 55 | 56 | static const char* TAG = "button"; 57 | /* DEFINITIONS ---------------------------------------------------------------*/ 58 | 59 | /* MACROS --------------------------------------------------------------------*/ 60 | 61 | /* PRIVATE FUNCTIONS DECLARATION ---------------------------------------------*/ 62 | static uint8_t button_index_find(uint8_t pin); 63 | 64 | /* FUNCTION PROTOTYPES -------------------------------------------------------*/ 65 | /** 66 | * @brief Initialize the button driver handler 67 | * 68 | * @param get_tick : function pointer that reads and returns the system tick 69 | * 70 | * @param gpio_read : fucntion pointer that reads and returns the state of the passed gpio pin 71 | */ 72 | void button_init(uint32_t* get_tick, uint8_t* gpio_read) 73 | { 74 | hButton.input_read = gpio_read; 75 | 76 | hButton.tick = get_tick; 77 | } 78 | /** 79 | * @brief Initialize a button with the given pin, pull type, and long-press duration. 80 | * 81 | * This function initializes a button by setting up its configuration with the given parameters. 82 | * The button configuration includes the GPIO pin, pull type, and the duration required to detect a long-press. 83 | * 84 | * @param pin The GPIO pin number to be associated with the button. 85 | * 86 | * @param pull_type either pull up = 1 or pull down = 0 87 | * 88 | * @param long_press_time_ms The duration in milliseconds required to detect a long-press event on the button. 89 | * 90 | * @param button_callback The duration in milliseconds required to detect a long-press event on the button. 91 | */ 92 | void button_add(uint8_t pin, uint8_t pull_type, uint32_t press_time, void* button_callback) 93 | { 94 | hw_buttons[button_index].config.pin = pin; 95 | 96 | hw_buttons[button_index].config.pull_type = pull_type; 97 | 98 | hw_buttons[button_index].config.long_press_time_ms = press_time; 99 | 100 | hw_buttons[button_index].callback = button_callback; 101 | 102 | ++button_index; 103 | } 104 | /** 105 | * @brief Perform button debounce to filter out spurious button state changes. 106 | * 107 | * This function performs debounce logic on the input button pin to filter out 108 | * spurious button state changes that can occur due to mechanical button bouncing. 109 | * 110 | * @param pin The GPIO pin number of the button to debounce. 111 | * 112 | * @return bool Returns ENABLE if the button state is stable (debounced) and considered valid. 113 | * Returns DISABLE if the button state is still unstable due to bouncing. 114 | * 115 | * @note The debounce logic maintains an internal level variable to track the stability 116 | * of the button state. The debounce time is determined by the start_boundry and end_boundry 117 | * constants defined within the function. Adjust these constants based on the desired debounce duration. 118 | * The function uses the provided tick_value to track the time elapsed since the button state change. 119 | * To debounce multiple buttons, use a separate instance of this function for each button with its pin number. 120 | */ 121 | bool button_debounce(uint8_t pin) 122 | { 123 | bool ret = DISABLE; 124 | 125 | const uint16_t start_boundary = 500; 126 | const uint16_t end_boundary = 10000; 127 | 128 | const uint16_t middle_value = 4000; 129 | 130 | static uint16_t level = middle_value; 131 | 132 | uint8_t button_index = 0; 133 | 134 | button_index = button_index_find(pin); 135 | 136 | while(1) 137 | { 138 | if(hw_buttons[button_index].config.pull_type != hButton.input_read(hw_buttons[button_index].config.pin)) 139 | { 140 | ++level; 141 | } 142 | else 143 | { 144 | --level; 145 | 146 | if(level <= start_boundary) 147 | { 148 | level = middle_value; 149 | 150 | break; 151 | } 152 | } 153 | if(level >= end_boundary) 154 | { 155 | level = middle_value; 156 | 157 | ret = ENABLE; 158 | 159 | hw_buttons[button_index].state = BUTTON_PRESSED; 160 | 161 | hw_buttons[button_index].press_time = hButton.tick(); 162 | 163 | break; 164 | } 165 | } 166 | 167 | return ret; 168 | } 169 | /** 170 | * @brief number of registered buttons is owned by this layer 171 | * 172 | * @return the number of registered buttons 173 | */ 174 | uint8_t button_get_count(void) 175 | { 176 | return button_index; 177 | } 178 | /** 179 | * @brief initialize button handler variables content 180 | * 181 | * @param systick : system tick get function 182 | */ 183 | void button_manager_init(uint32_t* systick) 184 | { 185 | memset(&hw_buttons ,0 ,sizeof(button_t) * HARDWARE_BUTTON_COUNT); 186 | 187 | button_index = 0; 188 | 189 | hButton.tick = systick; 190 | } 191 | /** 192 | * @brief Obtain the stated of the required button whether it is pressed, long pressed or double clicked. 193 | * 194 | * @param pin : physical pin the button is connected to 195 | * 196 | * @return button_state_t the state of the button 197 | */ 198 | button_state_t button_state_get(uint8_t pin) 199 | { 200 | uint8_t button_index = 0; 201 | 202 | button_index = button_index_find(pin); 203 | 204 | return hw_buttons[button_index].state; 205 | } 206 | 207 | /** 208 | * @brief Handle all button related states and callbacks 209 | * 210 | */ 211 | void button_manager(void) 212 | { 213 | uint8_t button_count = button_get_count(); 214 | 215 | for(uint8_t i = 0; i < button_index; ++i) 216 | { 217 | if((hw_buttons[i].state == BUTTON_PRESSED) || (hw_buttons[i].state == BUTTON_LONG_PRESSED)) 218 | { 219 | if(hButton.input_read(hw_buttons[i].config.pin) == hw_buttons[i].config.pull_type) 220 | { 221 | hw_buttons[i].state = BUTTON_CLICKED; 222 | 223 | hw_buttons[i].callback(); 224 | 225 | hw_buttons[i].state = BUTTON_IDLE; 226 | } 227 | else if(hButton.tick() - hw_buttons[i].press_time > hw_buttons[i].config.long_press_time_ms ) 228 | { 229 | hw_buttons[i].state = BUTTON_LONG_PRESSED; 230 | 231 | hw_buttons[i].callback(); 232 | 233 | hw_buttons[i].state = BUTTON_IDLE; 234 | 235 | } 236 | } 237 | 238 | } 239 | } 240 | /** 241 | * @brief Find the index of a button configuration in the hardware button array. 242 | * 243 | * This function searches for the index of a button configuration in the hardware button array 244 | * based on the given GPIO pin number. 245 | * 246 | * @param pin The GPIO pin number of the button to find the configuration index for. 247 | * 248 | * @return uint8_t Returns the index of the button configuration in the hardware button array 249 | * if found, or HARDWARE_BUTTON_COUNT if the button configuration is not found. 250 | */ 251 | static uint8_t button_index_find(uint8_t pin) 252 | { 253 | uint8_t index = 0; 254 | 255 | for (; index < HARDWARE_BUTTON_COUNT; ++index) 256 | { 257 | if(hw_buttons[index].config.pin == pin) 258 | { 259 | break; 260 | } 261 | } 262 | return index; 263 | } 264 | 265 | 266 | 267 | /*************************************** USEFUL ELECTRONICS*****END OF FILE****/ 268 | -------------------------------------------------------------------------------- /main/hardware/button.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * USEFUL ELECTRONICS 4 | ******************************************************************************/ 5 | /** 6 | ****************************************************************************** 7 | * @file : button.h 8 | * @author : WARD ALMASARANI 9 | * @version : v.1.0 10 | * @date : Jul 30, 2023 11 | * @link : https://www.youtube.com/@usefulelectronics 12 | * Hold Ctrl button and click on the link to be directed to 13 | Useful Electronics YouTube channel 14 | ******************************************************************************/ 15 | 16 | #ifndef MAIN_BUTTON_H_ 17 | #define MAIN_BUTTON_H_ 18 | 19 | 20 | /* INCLUDES ------------------------------------------------------------------*/ 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include "gpio/gpio_config.h" 26 | #include "stdbool.h" 27 | /* MACROS --------------------------------------------------------------------*/ 28 | #define HARDWARE_BUTTON_COUNT 1 29 | #define HARDWARE_BUTTON_OFFSET 1 30 | 31 | #define ENABLE 1 32 | #define DISABLE 0 33 | /* ENUMORATIONS --------------------------------------------------------------*/ 34 | // Button states 35 | typedef enum 36 | { 37 | BUTTON_IDLE, 38 | BUTTON_PRESSED, 39 | BUTTON_CLICKED, 40 | BUTTON_DOUBLE_CLICKED, 41 | BUTTON_LONG_PRESSED 42 | } button_state_t; 43 | /* STRUCTURES & TYPEDEFS -----------------------------------------------------*/ 44 | 45 | /* VARIABLES -----------------------------------------------------------------*/ 46 | 47 | /* FUNCTIONS DECLARATION -----------------------------------------------------*/ 48 | /** 49 | * @brief Initialize a button with the given pin, pull type, and long-press duration. 50 | * 51 | * This function initializes a button by setting up its configuration with the given parameters. 52 | * The button configuration includes the GPIO pin, pull type, and the duration required to detect a long-press. 53 | * 54 | * @param pin The GPIO pin number to be associated with the button. 55 | * 56 | * @param pull_type either pull up = 1 or pull down = 0 57 | * 58 | * @param long_press_time_ms The duration in milliseconds required to detect a long-press event on the button. 59 | * 60 | * @param button_callback The duration in milliseconds required to detect a long-press event on the button. 61 | */ 62 | void button_add(uint8_t pin, uint8_t pull_type, uint32_t press_time, void* button_callback); 63 | /** 64 | * @brief Initialize the button driver handler 65 | * 66 | * @param get_tick : function pointer that reads and returns the system tick 67 | * 68 | * @param gpio_read : fucntion pointer that reads and returns the state of the passed gpio pin 69 | */ 70 | void button_init(uint32_t* get_tick, uint8_t* gpio_read); 71 | /** 72 | * @brief Perform button debounce to filter out spurious button state changes. 73 | * 74 | * This function performs debounce logic on the input button pin to filter out 75 | * spurious button state changes that can occur due to mechanical button bouncing. 76 | * 77 | * @param pin The GPIO pin number of the button to debounce. 78 | * 79 | * @return bool Returns ENABLE if the button state is stable (debounced) and considered valid. 80 | * Returns DISABLE if the button state is still unstable due to bouncing. 81 | * 82 | * @note The debounce logic maintains an internal level variable to track the stability 83 | * of the button state. The debounce time is determined by the start_boundry and end_boundry 84 | * constants defined within the function. Adjust these constants based on the desired debounce duration. 85 | * The function uses the provided tick_value to track the time elapsed since the button state change. 86 | * To debounce multiple buttons, use a separate instance of this function for each button with its pin number. 87 | */ 88 | bool button_debounce(uint8_t pin); 89 | /** 90 | * @brief Obtain the stated of the required button whether it is pressed, long pressed or double clicked. 91 | * 92 | * @param pin : physical pin the button is connected to 93 | * 94 | * @return button_state_t the state of the button 95 | */ 96 | button_state_t button_state_get(uint8_t pin); 97 | /** 98 | * @brief Handle all button related states and callbacks 99 | * 100 | */ 101 | void button_manager(void); 102 | 103 | //Button action click double click long press 104 | 105 | 106 | #endif /* MAIN_BUTTON_H_ */ 107 | 108 | /*************************************** USEFUL ELECTRONICS*****END OF FILE****/ 109 | -------------------------------------------------------------------------------- /main/hardware/hlk-ld1125h.c: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * USEFUL ELECTRONICS 4 | ******************************************************************************/ 5 | /** 6 | ****************************************************************************** 7 | * @file : hlk-ld1125h.c 8 | * @author : WARD ALMASARANI 9 | * @version : v.1.0 10 | * @date : Jul 25, 2023 11 | * @link : https://www.youtube.com/@usefulelectronics 12 | * Hold Ctrl button and click on the link to be directed to 13 | Useful Electronics YouTube channel 14 | ******************************************************************************/ 15 | 16 | 17 | /* INCLUDES ------------------------------------------------------------------*/ 18 | #include "hlk-ld1125h.h" 19 | #include "stdbool.h" 20 | /* PRIVATE STRUCTRES ---------------------------------------------------------*/ 21 | 22 | /* VARIABLES -----------------------------------------------------------------*/ 23 | 24 | /* DEFINITIONS ---------------------------------------------------------------*/ 25 | 26 | /* MACROS --------------------------------------------------------------------*/ 27 | 28 | /* PRIVATE FUNCTIONS DECLARATION ---------------------------------------------*/ 29 | 30 | /* FUNCTION PROTOTYPES -------------------------------------------------------*/ 31 | /** 32 | * @brief Extracts the distance value from the provided packet and also identifies the packet type. 33 | * 34 | * This function extracts the distance value from the packet and identifies the packet type. 35 | * The packet should be in the format "packet_type, dis=distance_value", where packet_type is a string 36 | * representing the type of the packet, and distance_value is a floating-point value representing the distance. 37 | * 38 | * @param packet The input packet from which the distance is to be extracted. 39 | * @param packet_type The character array where the packet type will be stored. 40 | * 41 | * @return The extracted distance value as a number in cm, or -1 if the distance value is not found. 42 | * 43 | * @note The packet_type array should be large enough to store the packet type (e.g., "mov" or "occ") and null-terminated. 44 | * @note The packet should have the format "packet_type, dis=distance_value" for successful extraction. 45 | * 46 | * @code 47 | * char packet[] = "occ, dis=5.75"; 48 | * char packet_type[4]; 49 | * float distance = extract_distance(packet, packet_type); 50 | * printf("Received packet type: %s, Distance: %.2f\n", packet_type, distance); 51 | * @endcode 52 | */ 53 | int16_t hlk_ld1125h_parse_packet(const uint8_t* packet, uint8_t* packet_type) 54 | { 55 | char* distance_str = strstr((char *)packet, DESTINATION_PACK); 56 | 57 | if (distance_str != NULL) 58 | { 59 | float distance; 60 | uint16_t cmDistance; 61 | 62 | sscanf(distance_str + 4, "%f", &distance); 63 | //Convert designates to cm value 64 | cmDistance = (uint16_t) (distance * 100); 65 | // Get the packet type (mov or occ) 66 | 67 | if(false == memcmp(packet, MOVEMENT_OCC, MOVEMENT_STRING_SIZE)) 68 | { 69 | *packet_type = occ; 70 | } 71 | else if(false == memcmp(packet, MOVEMENT_MOV, MOVEMENT_STRING_SIZE)) 72 | { 73 | *packet_type = mov; 74 | } 75 | 76 | // packet_type[distance_str - packet - 2] = '\0'; 77 | return cmDistance; 78 | } 79 | return -1; // Return -1.0 if distance value not found 80 | } 81 | 82 | /*************************************** USEFUL ELECTRONICS*****END OF FILE****/ 83 | -------------------------------------------------------------------------------- /main/hardware/hlk-ld1125h.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * USEFUL ELECTRONICS 4 | ******************************************************************************/ 5 | /** 6 | ****************************************************************************** 7 | * @file : hlk-ld1125h.h 8 | * @author : WARD ALMASARANI 9 | * @version : v.1.0 10 | * @date : Jul 25, 2023 11 | * @link : https://www.youtube.com/@usefulelectronics 12 | * Hold Ctrl button and click on the link to be directed to 13 | Useful Electronics YouTube channel 14 | ******************************************************************************/ 15 | 16 | #ifndef MAIN_HLK_LD1125H_H_ 17 | #define MAIN_HLK_LD1125H_H_ 18 | 19 | 20 | /* INCLUDES ------------------------------------------------------------------*/ 21 | #include 22 | #include 23 | /* MACROS --------------------------------------------------------------------*/ 24 | #define DESTINATION_PACK "dis=" 25 | 26 | #define MOVEMENT_OCC "occ" 27 | #define MOVEMENT_MOV "mov" 28 | 29 | #define MOVEMENT_STRING_SIZE 3 30 | /* ENUMORATIONS --------------------------------------------------------------*/ 31 | 32 | /* STRUCTURES & TYPEDEFS -----------------------------------------------------*/ 33 | typedef enum 34 | { 35 | occ = 0, 36 | mov, 37 | }move_type_e; 38 | /* VARIABLES -----------------------------------------------------------------*/ 39 | 40 | /* FUNCTIONS DECLARATION -----------------------------------------------------*/ 41 | /** 42 | * @brief Extracts the distance value from the provided packet and also identifies the packet type. 43 | * 44 | * This function extracts the distance value from the packet and identifies the packet type. 45 | * The packet should be in the format "packet_type, dis=distance_value", where packet_type is a string 46 | * representing the type of the packet, and distance_value is a floating-point value representing the distance. 47 | * 48 | * @param packet The input packet from which the distance is to be extracted. 49 | * @param packet_type The character array where the packet type will be stored. 50 | * 51 | * @return The extracted distance value as a number in cm, or -1 if the distance value is not found. 52 | * 53 | * @note The packet_type array should be large enough to store the packet type (e.g., "mov" or "occ") and null-terminated. 54 | * @note The packet should have the format "packet_type, dis=distance_value" for successful extraction. 55 | * 56 | * @code 57 | * char packet[] = "occ, dis=5.75"; 58 | * char packet_type[4]; 59 | * float distance = extract_distance(packet, packet_type); 60 | * printf("Received packet type: %s, Distance: %.2f\n", packet_type, distance); 61 | * @endcode 62 | */ 63 | int16_t hlk_ld1125h_parse_packet(const uint8_t* packet, uint8_t* packet_type); 64 | 65 | 66 | #endif /* MAIN_HLK_LD1125H_H_ */ 67 | 68 | /*************************************** USEFUL ELECTRONICS*****END OF FILE****/ 69 | -------------------------------------------------------------------------------- /main/hardware/rotary_encoder.c: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * USEFUL ELECTRONICS 4 | ******************************************************************************/ 5 | /** 6 | ****************************************************************************** 7 | * @file : rotary_encoder.c 8 | * @author : WARD ALMASARANI 9 | * @version : v.1.0 10 | * @date : Jan 30, 2023 11 | * @link : https://www.youtube.com/@usefulelectronics 12 | * Hold Ctrl button and click on the link to be directed to 13 | Useful Electronics YouTube channel 14 | ******************************************************************************/ 15 | 16 | 17 | /* INCLUDES ------------------------------------------------------------------*/ 18 | #include "rotary_encoder.h" 19 | #include "stdbool.h" 20 | /* PRIVATE STRUCTRES ---------------------------------------------------------*/ 21 | typedef struct 22 | { 23 | uint32_t eventCount; 24 | QueueHandle_t queue; 25 | void (*callback)(uint32_t encoderValue); 26 | }encoder_handler_t; 27 | /* VARIABLES -----------------------------------------------------------------*/ 28 | static const char *encoder = "encoder"; 29 | 30 | static pcnt_unit_handle_t pcnt_unit = NULL; 31 | 32 | encoder_handler_t hEncoder = {0}; 33 | 34 | /* DEFINITIONS ---------------------------------------------------------------*/ 35 | 36 | /* MACROS --------------------------------------------------------------------*/ 37 | 38 | /* PRIVATE FUNCTIONS DECLARATION ---------------------------------------------*/ 39 | static bool pcnt_on_reach(pcnt_unit_handle_t unit, const pcnt_watch_event_data_t *edata, void *user_ctx); 40 | 41 | /* FUNCTION PROTOTYPES -------------------------------------------------------*/ 42 | static bool pcnt_on_reach(pcnt_unit_handle_t unit, const pcnt_watch_event_data_t *edata, void *user_ctx) 43 | { 44 | BaseType_t high_task_wakeup; 45 | QueueHandle_t queue = (QueueHandle_t)user_ctx; 46 | // send event data to queue, from this interrupt callback 47 | xQueueSendFromISR(queue, &(edata->watch_point_value), &high_task_wakeup); 48 | return (high_task_wakeup == pdTRUE); 49 | } 50 | /** 51 | * @brief This tatsk will read the encoder position value every 250ms 52 | * 53 | */ 54 | void encoder_handler_task(void *param) 55 | { 56 | static int pulse_count = 5000; 57 | 58 | int static prev_pulse_count = 0; 59 | 60 | const uint8_t pulse_offest = 50; 61 | 62 | const uint8_t rotary_step = 4; 63 | 64 | bool encoder_direction = 0; 65 | 66 | static bool negative_pulse_falg = false; 67 | 68 | 69 | 70 | while (1) 71 | { 72 | 73 | pcnt_unit_get_count(pcnt_unit, &pulse_count); 74 | 75 | 76 | if(pulse_count < -1 || (negative_pulse_falg == true && pulse_count == 0)) 77 | { 78 | negative_pulse_falg = true; 79 | } 80 | else 81 | { 82 | negative_pulse_falg = false; 83 | } 84 | 85 | pulse_count = pulse_count > 0 ? pulse_count : pulse_count * -1; 86 | 87 | if((pulse_count - prev_pulse_count >= rotary_step) || (pulse_count - prev_pulse_count <= rotary_step * -1)) 88 | { 89 | 90 | if(negative_pulse_falg) 91 | { 92 | encoder_direction = pulse_count > prev_pulse_count ? false : true; 93 | 94 | ESP_LOGI(encoder, "negative"); 95 | } 96 | else 97 | { 98 | encoder_direction = pulse_count > prev_pulse_count ? true : false; 99 | ESP_LOGI(encoder, "Positive"); 100 | } 101 | 102 | hEncoder.callback(encoder_direction); 103 | 104 | // hEncoder.callback(pulse_count + pulse_offest); 105 | 106 | prev_pulse_count = pulse_count; 107 | 108 | ESP_LOGI(encoder, "pulse count %d , direction %d", pulse_count, encoder_direction); 109 | } 110 | 111 | 112 | vTaskDelay(50/portTICK_PERIOD_MS); 113 | } 114 | } 115 | /** 116 | * @brief Initialize pulse counter to interface rotary encoder. 117 | * 118 | * @param callback : the passed callback will be executed 119 | */ 120 | void encoder_init(void* callback) 121 | { 122 | ESP_LOGI(encoder, "install pcnt unit"); 123 | pcnt_unit_config_t unit_config = { 124 | .high_limit = EXAMPLE_PCNT_HIGH_LIMIT, 125 | .low_limit = EXAMPLE_PCNT_LOW_LIMIT, 126 | }; 127 | 128 | // gpio_config_t knob_button_config = { 129 | // .mode = GPIO_MODE_INPUT, 130 | // .pin_bit_mask = 1ULL << KNOB_BUTTON 131 | // }; 132 | // ESP_ERROR_CHECK(gpio_config(&knob_button_config)); 133 | 134 | 135 | ESP_ERROR_CHECK(pcnt_new_unit(&unit_config, &pcnt_unit)); 136 | 137 | ESP_LOGI(encoder, "set glitch filter"); 138 | pcnt_glitch_filter_config_t filter_config = { 139 | .max_glitch_ns = 1000, 140 | }; 141 | ESP_ERROR_CHECK(pcnt_unit_set_glitch_filter(pcnt_unit, &filter_config)); 142 | 143 | ESP_LOGI(encoder, "install pcnt channels"); 144 | pcnt_chan_config_t chan_a_config = { 145 | .edge_gpio_num = EXAMPLE_EC11_GPIO_A, 146 | .level_gpio_num = EXAMPLE_EC11_GPIO_B, 147 | }; 148 | pcnt_channel_handle_t pcnt_chan_a = NULL; 149 | ESP_ERROR_CHECK(pcnt_new_channel(pcnt_unit, &chan_a_config, &pcnt_chan_a)); 150 | pcnt_chan_config_t chan_b_config = { 151 | .edge_gpio_num = EXAMPLE_EC11_GPIO_B, 152 | .level_gpio_num = EXAMPLE_EC11_GPIO_A, 153 | }; 154 | pcnt_channel_handle_t pcnt_chan_b = NULL; 155 | ESP_ERROR_CHECK(pcnt_new_channel(pcnt_unit, &chan_b_config, &pcnt_chan_b)); 156 | 157 | ESP_LOGI(encoder, "set edge and level actions for pcnt channels"); 158 | ESP_ERROR_CHECK(pcnt_channel_set_edge_action(pcnt_chan_a, PCNT_CHANNEL_EDGE_ACTION_DECREASE, PCNT_CHANNEL_EDGE_ACTION_INCREASE)); 159 | ESP_ERROR_CHECK(pcnt_channel_set_level_action(pcnt_chan_a, PCNT_CHANNEL_LEVEL_ACTION_KEEP, PCNT_CHANNEL_LEVEL_ACTION_INVERSE)); 160 | ESP_ERROR_CHECK(pcnt_channel_set_edge_action(pcnt_chan_b, PCNT_CHANNEL_EDGE_ACTION_INCREASE, PCNT_CHANNEL_EDGE_ACTION_DECREASE)); 161 | ESP_ERROR_CHECK(pcnt_channel_set_level_action(pcnt_chan_b, PCNT_CHANNEL_LEVEL_ACTION_KEEP, PCNT_CHANNEL_LEVEL_ACTION_INVERSE)); 162 | 163 | ESP_LOGI(encoder, "add watch points and register callbacks"); 164 | 165 | 166 | int watch_points[] = {-50,-40,-30}; 167 | 168 | // memcpy(hEncoder.whatchPoints, watch_points, sizeof(watch_points)); 169 | 170 | for (size_t i = 0; i < sizeof(watch_points) / sizeof(watch_points[0]); i++) { 171 | ESP_ERROR_CHECK(pcnt_unit_add_watch_point(pcnt_unit, watch_points[i])); 172 | } 173 | pcnt_event_callbacks_t cbs = { 174 | .on_reach = pcnt_on_reach, 175 | }; 176 | hEncoder.queue = xQueueCreate(10, sizeof(int)); 177 | ESP_ERROR_CHECK(pcnt_unit_register_event_callbacks(pcnt_unit, &cbs, hEncoder.queue)); 178 | 179 | ESP_LOGI(encoder, "enable pcnt unit"); 180 | ESP_ERROR_CHECK(pcnt_unit_enable(pcnt_unit)); 181 | ESP_LOGI(encoder, "clear pcnt unit"); 182 | ESP_ERROR_CHECK(pcnt_unit_clear_count(pcnt_unit)); 183 | ESP_LOGI(encoder, "start pcnt unit"); 184 | ESP_ERROR_CHECK(pcnt_unit_start(pcnt_unit)); 185 | 186 | //External callback register. 187 | hEncoder.callback = callback; 188 | } 189 | 190 | /*************************************** USEFUL ELECTRONICS*****END OF FILE****/ 191 | -------------------------------------------------------------------------------- /main/hardware/rotary_encoder.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * USEFUL ELECTRONICS 4 | ******************************************************************************/ 5 | /** 6 | ****************************************************************************** 7 | * @file : rotary_encoder.h 8 | * @author : WARD ALMASARANI 9 | * @version : v.1.0 10 | * @date : Jan 30, 2023 11 | * @link : https://www.youtube.com/@usefulelectronics 12 | * Hold Ctrl button and click on the link to be directed to 13 | Useful Electronics YouTube channel 14 | ******************************************************************************/ 15 | 16 | #ifndef MAIN_ROTARY_ENCODER_H_ 17 | #define MAIN_ROTARY_ENCODER_H_ 18 | 19 | 20 | /* INCLUDES ------------------------------------------------------------------*/ 21 | #include "freertos/FreeRTOS.h" 22 | #include "freertos/task.h" 23 | #include "freertos/queue.h" 24 | #include "esp_log.h" 25 | #include "driver/pulse_cnt.h" 26 | #include "driver/gpio.h" 27 | /* MACROS --------------------------------------------------------------------*/ 28 | 29 | 30 | #define ENCODER_MAX_WHATCHPIONT_COINT 100 31 | 32 | #define EXAMPLE_PCNT_HIGH_LIMIT 50 33 | #define EXAMPLE_PCNT_LOW_LIMIT -50 34 | 35 | #define EXAMPLE_EC11_GPIO_A 9 36 | #define EXAMPLE_EC11_GPIO_B 10 37 | #define KNOB_BUTTON 6//13 38 | /* ENUMORATIONS --------------------------------------------------------------*/ 39 | 40 | /* STRUCTURES & TYPEDEFS -----------------------------------------------------*/ 41 | 42 | /* VARIABLES -----------------------------------------------------------------*/ 43 | 44 | /* FUNCTIONS DECLARATION -----------------------------------------------------*/ 45 | void encoder_init(void* callback); 46 | 47 | void encoder_handler_task(void *param); 48 | 49 | 50 | #endif /* MAIN_ROTARY_ENCODER_H_ */ 51 | 52 | /*************************************** USEFUL ELECTRONICS*****END OF FILE****/ 53 | -------------------------------------------------------------------------------- /main/idf_component.yml: -------------------------------------------------------------------------------- 1 | dependencies: 2 | idf: ">=4.4" 3 | lvgl/lvgl: "~8.3.0" 4 | esp_lcd_ili9341: "^1.0" 5 | esp_lcd_gc9a01: "^1.0" 6 | esp_lcd_touch_stmpe610: "^1.0" 7 | -------------------------------------------------------------------------------- /main/main.c: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * USEFUL ELECTRONICS 4 | ******************************************************************************/ 5 | /** 6 | ****************************************************************************** 7 | * @file : main.c 8 | * @author : WARD ALMASARANI 9 | * @version : v.1.0 10 | * @date : Jan 30, 2023 11 | * @link : https://www.youtube.com/@usefulelectronics 12 | * Hold Ctrl button and click on the link to be directed to 13 | Useful Electronics YouTube channel 14 | ******************************************************************************/ 15 | 16 | 17 | /* INCLUDES ------------------------------------------------------------------*/ 18 | #include "main.h" 19 | #include "extra/widgets/colorwheel/lv_colorwheel.h" 20 | #include "uart_config.h" 21 | #include "esp_interrupt.h" 22 | 23 | #include "hardware/rotary_encoder.h" 24 | #include "hardware/hlk-ld1125h.h" 25 | #include "hardware/button.h" 26 | #include "hardware/hlk-ld1125h.h" 27 | 28 | #include "display/display.h" 29 | #include "display/gc9a01.h" 30 | #include "display/lvgl_demo_ui.h" 31 | #include "display/ui_helpers.h" 32 | 33 | #include "wireless/sntp.h" 34 | 35 | 36 | #include "time.h" 37 | #include 38 | #include "lwip/ip_addr.h" 39 | #include "timer/systimer.h" 40 | 41 | #include "gpio/gpio_config.h" 42 | #include "esp_log.h" 43 | #include 44 | 45 | 46 | /* MACROS --------------------------------------------------------------------*/ 47 | #define SYSTEM_BUFFER_SIZE 4 48 | #define SYSTEM_ROTARY_ENCODER_STEP_SIZE 4 49 | #define SYSTEM_LAMP_MODE_COUNT 3 //see lv_colorwheel_mode_t 50 | /* DEFINITIONS ---------------------------------------------------------------*/ 51 | 52 | /* PRIVATE STRUCTRES ---------------------------------------------------------*/ 53 | typedef struct 54 | { 55 | uint8_t packet_size; 56 | uint16_t data[SYSTEM_BUFFER_SIZE]; 57 | }system_packet; 58 | 59 | typedef struct { 60 | int16_t hue; 61 | int8_t saturation; 62 | int8_t brightness; 63 | } system_hsv_t; 64 | 65 | typedef struct 66 | { 67 | bool on_state; 68 | system_hsv_t color; 69 | uint32_t encoder_rotary_angle; 70 | uint8_t control_mode; 71 | }system_lamp_data_t; 72 | 73 | char main_mqtt_topic_buffer[50]; 74 | /* VARIABLES -----------------------------------------------------------------*/ 75 | static const char *main = "main"; 76 | char targetString[10] = {0}; 77 | 78 | static const char* TAG = "main"; 79 | static system_lamp_data_t hLamp = {0}; 80 | static QueueHandle_t system_queue; 81 | 82 | TaskHandle_t hMain_uiTask = NULL; 83 | TaskHandle_t hMain_eventTask = NULL; 84 | /* PRIVATE FUNCTIONS DECLARATION ---------------------------------------------*/ 85 | static void time_config(void); 86 | static void main_encoder_cb(uint32_t knobPosition); 87 | static void main_tempretureStringPrepare(char* tempString, char* targetString); 88 | static void lvgl_time_task(void*param); 89 | static void wirless_init_task(void* param); 90 | static void mqtt_msg_pars_task(void* param); 91 | static void time_handle_task(void* param); 92 | static void uart_reception_task(void *param); 93 | static void event_handle_task(void* param); 94 | static void main_system_timer_task(void* param); 95 | 96 | static void main_rotary_button_event(void); 97 | static uint32_t main_get_systick(void); 98 | static char* main_mqtt_topic_string (uint16_t device_index, char* mqtt_topic); 99 | static void main_lamp_init(void); 100 | static void main_lamp_param_update(void); 101 | 102 | /* FUNCTION PROTOTYPES -------------------------------------------------------*/ 103 | /** 104 | * @brief Initialize system peripherals and create FreeRTOS tasks 105 | * 106 | */ 107 | void app_main(void) 108 | { 109 | 110 | gc9a01_displayInit(); 111 | 112 | displayConfig(); 113 | 114 | main_lamp_init(); 115 | 116 | systimer_init(); 117 | 118 | //uart_config(); 119 | 120 | gpio_config_ext_interrupt(KNOB_BUTTON, GPIO_INTR_NEGEDGE, gpio_isr_handle); 121 | 122 | button_init(main_get_systick, gpio_get_level); 123 | button_add(KNOB_BUTTON, 1, 1500, main_rotary_button_event); 124 | 125 | encoder_init(main_encoder_cb); 126 | 127 | system_queue = xQueueCreate(10, sizeof(system_packet)); 128 | 129 | xTaskCreatePinnedToCore(wirless_init_task, "WiFi init", 10000, NULL, 4, NULL, 0); 130 | 131 | xTaskCreatePinnedToCore(encoder_handler_task, "encoder_handler", 10000, NULL, 4, NULL, 1); 132 | 133 | // xTaskCreatePinnedToCore(lvgl_time_task, "lvgl_time_task", 10000, NULL, 4, NULL, 1); 134 | 135 | //Wait for WiFi and MQTT broker connection to be established. 136 | // vTaskDelay(pdMS_TO_TICKS(15000)); 137 | 138 | // sntp_config(); 139 | 140 | vTaskDelay(pdMS_TO_TICKS(15000)); 141 | 142 | xTaskCreatePinnedToCore(lvgl_time_task, "lvgl_time_task", 10000, NULL, 4, NULL, 1); 143 | 144 | xTaskCreatePinnedToCore(mqtt_msg_pars_task, "MQTT parser", 10000, NULL, 4, NULL, 1); 145 | 146 | xTaskCreatePinnedToCore(main_system_timer_task, "system timer task", 10000, NULL, 4, NULL, 1); 147 | 148 | //xTaskCreatePinnedToCore(time_handle_task, "Real time Handler", 10000, NULL, 4, NULL, 1); 149 | 150 | xTaskCreatePinnedToCore(event_handle_task, "lvgl_time_task", 10000, NULL, 4, &hMain_eventTask, 1); 151 | } 152 | /** 153 | * @brief LVGL library timer task. Necessary to run once every 10ms 154 | * 155 | */ 156 | void lvgl_time_task(void* param) 157 | { 158 | TickType_t xLastWakeTime = xTaskGetTickCount(); 159 | 160 | system_packet system_buffer = {0}; 161 | while(1) 162 | { 163 | 164 | // The task running lv_timer_handler should have lower priority than that running `lv_tick_inc` 165 | lv_timer_handler(); 166 | // //Used with smart watch 167 | // _ui_arc_increment(); 168 | 169 | button_manager(); 170 | 171 | // raise the task priority of LVGL and/or reduce the handler period can improve the performance 172 | 173 | vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(10) ); 174 | 175 | } 176 | } 177 | /** 178 | * @brief Encoder position read callback. 179 | * 180 | * @param knobPosition : Read encoder position value. 181 | */ 182 | static void main_encoder_cb(uint32_t knobPosition) 183 | { 184 | static uint32_t prev_encoder_value = 0; 185 | 186 | int8_t temp_rotation_direction = 0; 187 | 188 | if(!knobPosition) 189 | { 190 | temp_rotation_direction = SYSTEM_ROTARY_ENCODER_STEP_SIZE; 191 | 192 | } 193 | else 194 | { 195 | temp_rotation_direction = SYSTEM_ROTARY_ENCODER_STEP_SIZE * -1; 196 | 197 | } 198 | switch (hLamp.control_mode) 199 | { 200 | case 0: 201 | hLamp.color.hue += temp_rotation_direction; 202 | 203 | hLamp.color.hue = fmax(0, fmin(360, hLamp.color.hue)); 204 | break; 205 | 206 | case 1: 207 | hLamp.color.saturation += temp_rotation_direction; 208 | 209 | hLamp.color.saturation = fmax(0, fmin(100, hLamp.color.saturation)); 210 | break; 211 | 212 | case 2: 213 | hLamp.color.brightness += temp_rotation_direction; 214 | 215 | // Clamp brightness between 0 and 100 216 | hLamp.color.brightness = fmax(0, fmin(100, hLamp.color.brightness)); 217 | break; 218 | } 219 | 220 | //Start timer to publish light data after 1 s time out 221 | 222 | ui_set_wheel_color( &hLamp.color); 223 | 224 | systimer_start(40, 1, main_lamp_param_update); 225 | 226 | ESP_LOGI(TAG, "hue value %d brightness value %d sat value %d step value %d mode %d", hLamp.color.hue, hLamp.color.brightness ,hLamp.color.saturation, temp_rotation_direction, hLamp.control_mode); 227 | 228 | //ui_set_wheel_mode(hLamp.control_mode); 229 | 230 | prev_encoder_value = knobPosition; 231 | // set_value((int32_t) knobPosition, knobButtonStatus); 232 | } 233 | 234 | static void uart_reception_task(void *param) 235 | { 236 | uartHandler_t uartHandler = {0}; 237 | 238 | uint8_t movementType = 0; 239 | 240 | int16_t detectedDistance = 0; 241 | 242 | system_packet system_buffer = {0}; 243 | for(;;) 244 | { 245 | //Waiting for UART packet to get received. 246 | if(xQueueReceive(uartRxStore_queue, (void * )&uartHandler, portMAX_DELAY)) 247 | { 248 | detectedDistance = hlk_ld1125h_parse_packet(hUart.uart_rxBuffer,(uint8_t*) &movementType); 249 | 250 | if(-1 != detectedDistance) 251 | { 252 | // ESP_LOGI(main, "dis = %d, move type %d", detectedDistance, movementType); 253 | 254 | system_buffer.data[0] = detectedDistance; 255 | system_buffer.data[1] = movementType; 256 | 257 | system_buffer.packet_size = 2; 258 | 259 | xQueueSendToBack(system_queue, &system_buffer, portMAX_DELAY); 260 | } 261 | } 262 | } 263 | } 264 | 265 | /** 266 | * @brief Initialize WiFi and connect to The configured WiFi network. and then connect to the MQTT broker 267 | * 268 | */ 269 | static void wirless_init_task(void* param) 270 | { 271 | wifi_connect(); 272 | 273 | mqtt_app_start(); 274 | 275 | vTaskDelete(NULL); 276 | } 277 | 278 | static void main_system_timer_task(void* param) 279 | { 280 | TickType_t xLastWakeTime = xTaskGetTickCount(); 281 | 282 | while(1) 283 | { 284 | vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(10)); 285 | 286 | systimer_tick_handler(); 287 | } 288 | } 289 | 290 | static void mqtt_msg_pars_task(void* param) 291 | { 292 | mqtt_buffer_t mqttBuffer = {0}; 293 | 294 | const char publishRequest = 1; 295 | 296 | while(1) 297 | { 298 | if(xQueueReceive(mqttSubscribe_queue, (void *)&mqttBuffer, portMAX_DELAY)) 299 | { 300 | switch (mqttBuffer.eventType) 301 | { 302 | case MQTT_BROKER_CONNECT: 303 | //_ui_text_wifiIndicate(true); 304 | main_mqtt_topic_string (1, MQTT_LAMP_GETHSV); 305 | 306 | mqtt_publish(main_mqtt_topic_string (1, MQTT_LAMP_GETHSV), &publishRequest, 0); 307 | 308 | ui_set_mqtt_switch_state(true); 309 | break; 310 | case MQTT_BROKER_DISCONNECT: 311 | //_ui_text_wifiIndicate(false); 312 | ui_set_mqtt_switch_state(false); 313 | break; 314 | case MQTT_TOPIC_DATA_RX: 315 | if(strcmp(mqttBuffer.topicString, main_mqtt_topic_string (1, MQTT_LAMP_GETHSV))) 316 | { 317 | sscanf(mqttBuffer.data, "%d, %d, %d",(int*) &hLamp.color.hue, (int*) &hLamp.color.saturation, (int*) &hLamp.color.brightness); 318 | 319 | ESP_LOGI(TAG, "mqtt set hsv %s", mqttBuffer.data); 320 | 321 | ui_set_wheel_color( &hLamp.color); 322 | 323 | ESP_LOGI(TAG, "MQTT_LAMP_GETHSV, "); 324 | } 325 | else if(strcmp(mqttBuffer.topicString, main_mqtt_topic_string (1, MQTT_LAMP_GETON))) 326 | { 327 | bool lamp_status = atoi(mqttBuffer.data); 328 | 329 | ui_set_lamp_state(lamp_status); 330 | 331 | hLamp.on_state = lamp_status; 332 | 333 | ESP_LOGI(TAG, "mqtt set status %s", mqttBuffer.data); 334 | } 335 | 336 | break; 337 | default: 338 | break; 339 | } 340 | } 341 | } 342 | } 343 | 344 | static void time_handle_task(void* param) 345 | { 346 | struct tm Time = {0}; 347 | 348 | char tempString[3] = {0}; 349 | 350 | TickType_t xLastWakeTime = xTaskGetTickCount(); 351 | 352 | const uint32_t tempUpdatePeriod = 60 * 60; //1 hour 353 | 354 | static uint32_t tempUpdateCounter = 0; 355 | 356 | const char publishRequest = 1; 357 | while(1) 358 | { 359 | vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(1000) ); 360 | 361 | sntp_time_get(&Time); 362 | 363 | sprintf(tempString,"%02d",Time.tm_hour); 364 | 365 | realTime.sel.hour = (tempString[1] << 8); 366 | realTime.sel.hour |= (tempString[0]); 367 | 368 | sprintf(tempString,"%02d",Time.tm_min); 369 | 370 | realTime.sel.minute = (tempString[1] << 8); 371 | realTime.sel.minute |= (tempString[0]); 372 | 373 | ++tempUpdateCounter; 374 | 375 | if(tempUpdatePeriod <= tempUpdateCounter) 376 | { 377 | mqtt_publish(MQTT_REQUEST_TOPIC, &publishRequest, 1); 378 | 379 | tempUpdateCounter = 0; 380 | } 381 | 382 | } 383 | } 384 | static void event_handle_task(void* param) 385 | { 386 | while(1) 387 | { 388 | //Note: CallbackID is cleared immediately after executing this task 389 | if(xTaskNotifyWait(0, ULONG_MAX, &interrupt_id, portMAX_DELAY )) 390 | { 391 | switch (interrupt_id) 392 | { 393 | case EXT_GPIO_INT: 394 | button_debounce(KNOB_BUTTON); 395 | break; 396 | 397 | default: 398 | break; 399 | } 400 | } 401 | } 402 | } 403 | 404 | /** 405 | * @brief Create a proper temperature value showing string 406 | * 407 | * @param tempString : string received over MQTT 408 | * 409 | * @param targetString: string to copy the formed string to 410 | */ 411 | static void main_tempretureStringPrepare(char* tempString, char* targetString) 412 | { 413 | const char tempUnit[4] = " °C"; 414 | const char tempStingLength = 3; 415 | for(uint8_t i = 0; i < tempStingLength; ++i) 416 | { 417 | if(!isalnum((int)tempString[i])) 418 | { 419 | strcpy(&tempString[i], tempUnit); 420 | break; 421 | } 422 | } 423 | 424 | strcpy(targetString,tempString); 425 | 426 | targetString[6] = 0; 427 | 428 | } 429 | static void main_rotary_button_event(void) 430 | { 431 | char temp_publish_string[5] = {0}; 432 | button_state_t button_state = button_state_get(KNOB_BUTTON); 433 | if(button_state == BUTTON_CLICKED) 434 | { 435 | ESP_LOGI(TAG, "Button pressed"); 436 | //reverse value for state toggling 437 | hLamp.on_state ^= 1; 438 | 439 | ui_set_lamp_state(hLamp.on_state); 440 | 441 | sprintf(temp_publish_string, "%d",hLamp.on_state); 442 | 443 | mqtt_publish(MQTT_LAMP_SETON, temp_publish_string , strlen(temp_publish_string)); 444 | 445 | //Change wheel mode 446 | 447 | } 448 | else if (button_state == BUTTON_LONG_PRESSED) 449 | { 450 | ++hLamp.control_mode; 451 | 452 | if(hLamp.control_mode >= SYSTEM_LAMP_MODE_COUNT) 453 | { 454 | hLamp.control_mode = 0; 455 | } 456 | 457 | ui_set_wheel_mode(hLamp.control_mode); 458 | 459 | 460 | ESP_LOGI(TAG, "Button long pressed"); 461 | } 462 | } 463 | static uint32_t main_get_systick(void) 464 | { 465 | return SYS_TICK(); 466 | } 467 | 468 | static char* main_mqtt_topic_string (uint16_t device_index, char* mqtt_topic) 469 | { 470 | memset(main_mqtt_topic_buffer, 0, sizeof(main_mqtt_topic_buffer)); 471 | 472 | sprintf(main_mqtt_topic_buffer, "%d%s", device_index, mqtt_topic); 473 | 474 | return main_mqtt_topic_buffer; 475 | } 476 | 477 | static void main_lamp_init(void) 478 | { 479 | hLamp.color.brightness = 100; 480 | hLamp.color.saturation = 100; 481 | hLamp.control_mode = 0; 482 | } 483 | 484 | static void main_lamp_param_update(void) 485 | { 486 | char temp_publish_string[30] = {0}; 487 | 488 | sprintf(temp_publish_string, "%d, %d, %d", hLamp.color.hue, hLamp.color.saturation, hLamp.color.brightness); 489 | 490 | mqtt_publish(MQTT_LAMP_SETHSV, temp_publish_string , strlen(temp_publish_string)); 491 | } 492 | /*************************************** USEFUL ELECTRONICS*****END OF FILE****/ 493 | -------------------------------------------------------------------------------- /main/main.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * USEFUL ELECTRONICS 4 | ******************************************************************************/ 5 | /** 6 | ****************************************************************************** 7 | * @file : main.h 8 | * @author : WARD ALMASARANI 9 | * @version : v.1.0 10 | * @date : Jan 30, 2023 11 | * @link : https://www.youtube.com/@usefulelectronics 12 | * Hold Ctrl button and click on the link to be directed to 13 | Useful Electronics YouTube channel 14 | ******************************************************************************/ 15 | 16 | #ifndef MAIN_MAIN_H_ 17 | #define MAIN_MAIN_H_ 18 | 19 | 20 | /* INCLUDES ------------------------------------------------------------------*/ 21 | #include "wireless/wifi_connect.h" 22 | #include "wireless/mqtt.h" 23 | #include 24 | #include 25 | /* MACROS --------------------------------------------------------------------*/ 26 | #define SYS_TICK() xTaskGetTickCount() * portTICK_PERIOD_MS 27 | /* ENUMORATIONS --------------------------------------------------------------*/ 28 | typedef enum 29 | { 30 | noti_idle = 0, 31 | noti_button, 32 | noti_rotary_left, 33 | noti_rotary_right, 34 | }notification_e; 35 | /* STRUCTURES & TYPEDEFS -----------------------------------------------------*/ 36 | 37 | /* VARIABLES -----------------------------------------------------------------*/ 38 | extern TaskHandle_t hMain_uiTask; 39 | extern TaskHandle_t hMain_eventTask; 40 | /* FUNCTIONS DECLARATION -----------------------------------------------------*/ 41 | 42 | 43 | 44 | #endif /* MAIN_MAIN_H_ */ 45 | 46 | /*************************************** USEFUL ELECTRONICS*****END OF FILE****/ 47 | -------------------------------------------------------------------------------- /main/timer/systimer.c: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * USEFUL ELECTRONICS 4 | ******************************************************************************/ 5 | /** 6 | ****************************************************************************** 7 | * @file : systimer.c 8 | * @author : WARD ALMASARANI 9 | * @version : v.1.0 10 | * @date : Dec 5, 2024 11 | * @link : https://www.youtube.com/@usefulelectronics 12 | * Hold Ctrl button and click on the link to be directed to 13 | Useful Electronics YouTube channel 14 | ******************************************************************************/ 15 | 16 | 17 | /* INCLUDES ------------------------------------------------------------------*/ 18 | #include "systimer.h" 19 | #include 20 | #include 21 | /* PRIVATE STRUCTRES ---------------------------------------------------------*/ 22 | 23 | typedef struct 24 | { 25 | uint32_t duration; // Timer duration in ticks 26 | uint32_t remaining_ticks; // Remaining ticks 27 | bool is_active; // Timer active status 28 | int32_t repeat_count; // Number of times the timer repeats (-1 for continuous) 29 | systimer_callback callback; // Function to call on expiry 30 | } systimer_t; 31 | /* VARIABLES -----------------------------------------------------------------*/ 32 | systimer_t systimer[SYSTIMER_MAX_TIMERS_COUNT] = {0}; 33 | /* DEFINITIONS ---------------------------------------------------------------*/ 34 | 35 | /* MACROS --------------------------------------------------------------------*/ 36 | 37 | /* PRIVATE FUNCTIONS DECLARATION ---------------------------------------------*/ 38 | 39 | /* FUNCTION PROTOTYPES -------------------------------------------------------*/ 40 | void systimer_tick_handler(void) 41 | { 42 | for (int i = 0; i < SYSTIMER_MAX_TIMERS_COUNT; i++) 43 | { 44 | if (systimer[i].is_active) 45 | { 46 | if (systimer[i].remaining_ticks > 0) 47 | { 48 | systimer[i].remaining_ticks--; 49 | if (systimer[i].remaining_ticks == 0) 50 | { 51 | //systimer[i].is_active = false; 52 | if (NULL != systimer[i].callback) 53 | { 54 | systimer[i].callback(); // Call the callback 55 | } 56 | if (systimer[i].repeat_count == 0) 57 | { 58 | systimer[i].is_active = false; // Stop timer if no repeats left 59 | } 60 | else 61 | { 62 | if (systimer[i].repeat_count > 0) 63 | { 64 | systimer[i].repeat_count--; // Decrement repeat count 65 | } 66 | systimer[i].remaining_ticks = systimer[i].duration; // Reset timer 67 | } 68 | } 69 | } 70 | } 71 | } 72 | } 73 | 74 | 75 | void systimer_init(void) 76 | { 77 | for (uint8_t i = 0; i < SYSTIMER_MAX_TIMERS_COUNT; i++) 78 | { 79 | systimer[i].is_active = false; 80 | systimer[i].remaining_ticks = 0; 81 | systimer[i].duration = 0; 82 | systimer[i].repeat_count = 0; 83 | systimer[i].callback = NULL; 84 | } 85 | } 86 | 87 | int8_t systimer_start(uint32_t duration, int32_t repeatCount, systimer_callback callback) 88 | { 89 | // Check for an existing timer with the same properties 90 | for (uint8_t i = 0; i < SYSTIMER_MAX_TIMERS_COUNT; i++) { 91 | if (systimer[i].is_active && 92 | systimer[i].duration == duration && 93 | systimer[i].repeat_count == repeatCount && 94 | systimer[i].callback == callback) 95 | { 96 | 97 | // Restart the existing timer 98 | systimer[i].remaining_ticks = duration; 99 | systimer[i].is_active = true; 100 | return i; // Return the existing timer ID 101 | } 102 | } 103 | // Find an available timer slot 104 | for (int8_t i = 0; i < SYSTIMER_MAX_TIMERS_COUNT; i++) 105 | { 106 | if (!systimer[i].is_active) 107 | { 108 | systimer[i].duration = duration; 109 | systimer[i].remaining_ticks = duration; 110 | systimer[i].repeat_count = repeatCount; 111 | systimer[i].callback = callback; 112 | systimer[i].is_active = true; 113 | return i; // Return timer ID 114 | } 115 | } 116 | return -1; // No available timer slots 117 | } 118 | 119 | void systimer_stop(int8_t systimer_id) 120 | { 121 | if (systimer >= 0 && systimer_id < SYSTIMER_MAX_TIMERS_COUNT) 122 | { 123 | systimer[systimer_id].is_active = false; 124 | } 125 | } 126 | 127 | /*************************************** USEFUL ELECTRONICS*****END OF FILE****/ 128 | -------------------------------------------------------------------------------- /main/timer/systimer.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * USEFUL ELECTRONICS 4 | ******************************************************************************/ 5 | /** 6 | ****************************************************************************** 7 | * @file : systimer.h 8 | * @author : WARD ALMASARANI 9 | * @version : v.1.0 10 | * @date : Dec 5, 2024 11 | * @link : https://www.youtube.com/@usefulelectronics 12 | * Hold Ctrl button and click on the link to be directed to 13 | Useful Electronics YouTube channel 14 | ******************************************************************************/ 15 | 16 | #ifndef MAIN_TIMER_SYSTIMER_H_ 17 | #define MAIN_TIMER_SYSTIMER_H_ 18 | 19 | 20 | /* INCLUDES ------------------------------------------------------------------*/ 21 | #include 22 | #include 23 | /* MACROS --------------------------------------------------------------------*/ 24 | #define SYSTIMER_MAX_TIMERS_COUNT 10 25 | /* ENUMORATIONS --------------------------------------------------------------*/ 26 | 27 | /* STRUCTURES & TYPEDEFS -----------------------------------------------------*/ 28 | typedef void (*systimer_callback)(void); 29 | /* VARIABLES -----------------------------------------------------------------*/ 30 | 31 | /* FUNCTIONS DECLARATION -----------------------------------------------------*/ 32 | /** 33 | * @brief System timer tick handler. 34 | * 35 | * This function is called periodically by the system tick. It decrements the remaining ticks 36 | * for each active timer, executes the callback function if a timer expires, and handles 37 | * repeating timers based on their repeat count. 38 | 39 | * Timers with a repeat count of `-1` will continue to reset indefinitely, making them 40 | * continuous timers. 41 | * 42 | * @note This function must be called in a time-critical context, such as from a tick interrupt 43 | * or a high-priority task. 44 | */ 45 | void systimer_tick_handler(void); 46 | /** 47 | * @brief Initializes the system timer module. 48 | * 49 | * This function resets all system timers to their default inactive state. 50 | * It ensures that all timers are deactivated, their remaining ticks and durations are set to zero, 51 | * repeat counts are cleared, and their callback functions are set to NULL. 52 | * This function should be called during system initialization before any timers are used. 53 | */ 54 | void systimer_init(void); 55 | /** 56 | * @brief Starts a system timer with the specified configuration. 57 | * 58 | * This function starts a timer with the given `duration`, `repeatCount`, and `callback`. 59 | * If a timer with the same configuration (duration, repeat count, and callback) already exists, 60 | * it restarts the existing timer instead of creating a new one. 61 | * If no available slots exist for a new timer, the function returns an error. 62 | * 63 | * @param[in] duration The duration of the timer in ticks. 64 | * @param[in] repeatCount The number of times the timer should repeat: 65 | * - `> 0`: Number of repetitions. 66 | * - `0`: One-shot timer (runs once). 67 | * - `-1`: Continuous timer (repeats indefinitely). 68 | * @param[in] callback The function to be called when the timer expires. 69 | * 70 | * @return int8_t The ID of the started or restarted timer: 71 | * - `>= 0`: Timer ID (valid index in the timer array). 72 | * - `-1`: No available timer slots or an error occurred. 73 | */ 74 | int8_t systimer_start(uint32_t duration, int32_t repeatCount, systimer_callback callback); 75 | /** 76 | * @brief Stops an active system timer. 77 | * 78 | * This function deactivates the specified timer by its ID, preventing it from 79 | * triggering further callbacks. The timer's configuration remains intact and 80 | * can be restarted using its ID. 81 | * 82 | * @param[in] systimer_id The ID of the timer to stop. Must be a valid ID 83 | * within the range [0, SYSTIMER_MAX_TIMERS_COUNT - 1]. 84 | */ 85 | void systimer_stop(int8_t systimer_id); 86 | 87 | 88 | #endif /* MAIN_TIMER_SYSTIMER_H_ */ 89 | 90 | /*************************************** USEFUL ELECTRONICS*****END OF FILE****/ 91 | -------------------------------------------------------------------------------- /main/uart_config.c: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | ****************************************************************************** 4 | * @Channel Link : https://www.youtube.com/user/wardzx1 5 | * @file : uart.c 6 | * @author : Ward Almasarani - Useful Electronics 7 | * @version : v.1.0 8 | * @date : Sep 5, 2022 9 | * @brief : 10 | * 11 | ******************************************************************************/ 12 | 13 | 14 | /* INCLUDES ------------------------------------------------------------------*/ 15 | #include "uart_config.h" 16 | /* PRIVATE STRUCTRES ---------------------------------------------------------*/ 17 | 18 | /* VARIABLES -----------------------------------------------------------------*/ 19 | QueueHandle_t uartRx_queue; 20 | QueueHandle_t uartRxStore_queue; 21 | QueueHandle_t uartTx_queue; 22 | SemaphoreHandle_t UART_RXsem = NULL; 23 | /* DEFINITIONS ---------------------------------------------------------------*/ 24 | 25 | /* MACROS --------------------------------------------------------------------*/ 26 | 27 | /* PRIVATE FUNCTIONS DECLARATION ---------------------------------------------*/ 28 | const char *UART_DEBUG = "UART"; 29 | uartHandler_t hUart; 30 | /* FUNCTION PROTOTYPES -------------------------------------------------------*/ 31 | /** 32 | * @brief initialize UART handler 33 | * 34 | */ 35 | void uartBufferInit(void) 36 | { 37 | memset(&hUart, 0,sizeof(uartHandler_t)); 38 | } 39 | /** 40 | * @brief Get a copy from the received data over UART 41 | * 42 | * @param buffer : Pointer to the UART RX buffer 43 | * 44 | * @return The size of the received packet 45 | */ 46 | uint8_t uartGetRxBuffer(uint8_t* buffer) 47 | { 48 | memcpy(buffer, hUart.uart_rxBuffer, hUart.uart_rxPacketSize); 49 | 50 | return hUart.uart_rxPacketSize; 51 | } 52 | /** 53 | * @brief check if a new packet has been received 54 | * 55 | * @return packet reception status flag 56 | */ 57 | uint8_t uartCheckPacketRxFlag(void) 58 | { 59 | return hUart.uart_status.flags.rxPacket; 60 | } 61 | /** 62 | * @brief reset packet reception flag 63 | * 64 | */ 65 | void uartResetPacketRxFlag(void) 66 | { 67 | hUart.uart_status.flags.rxPacket = 0; 68 | } 69 | /** 70 | * @brief Configure UART peripheral of ESP32 71 | * 72 | */ 73 | void uart_config(void) 74 | { 75 | const uart_config_t uart_config = 76 | { 77 | //TODO //Baud rate must be set to 115200 for PingPong Example 78 | .baud_rate = 115200, 79 | .data_bits = UART_DATA_8_BITS, 80 | .parity = UART_PARITY_DISABLE, 81 | .stop_bits = UART_STOP_BITS_1, 82 | .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, 83 | .source_clk = UART_SCLK_DEFAULT, 84 | }; 85 | // We won't use a buffer for sending data. 86 | uart_driver_install(UART_AT_PORT, RX_BUF_SIZE * 2, TX_BUF_SIZE * 2, 20, &uartRx_queue, 0); 87 | uart_param_config(UART_AT_PORT, &uart_config); 88 | uart_set_pin(UART_AT_PORT, TXD_PIN, RXD_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); 89 | 90 | //Set uart pattern detect function. 91 | // uart_enable_pattern_det_baud_intr(UART_AT_PORT, '\n', PATTERN_AT_COUNT, 2, 0, 0); 92 | //Reset the pattern queue length to record at most 20 pattern positions. 93 | // uart_pattern_queue_reset(UART_AT_PORT, 100); 94 | 95 | uartBufferInit(); 96 | 97 | uartTx_queue = xQueueCreate(10, sizeof(uartHandler_t)); 98 | uartRxStore_queue = xQueueCreate(10, sizeof(uartHandler_t)); 99 | } 100 | /** 101 | * @brief UART TX function. The transmission starts once the related queue is filled. 102 | * 103 | * @param pvParameters 104 | */ 105 | void uart_transmission_task(void *pvParameters) 106 | { 107 | int dataTransmitted = 0; 108 | while(1) 109 | { 110 | if(xQueueReceive(uartTx_queue, (void *)&hUart, portMAX_DELAY)) 111 | { 112 | 113 | dataTransmitted = uart_write_bytes(UART_AT_PORT, hUart.uart_txBuffer, hUart.uart_txPacketSize); 114 | 115 | vTaskDelay(150/portTICK_PERIOD_MS); 116 | } 117 | } 118 | } 119 | 120 | 121 | /** 122 | * @brief UART event task. Here UART RX callback takes place. This task should be started in the main 123 | * 124 | * @param pvParameters 125 | */ 126 | void uart_event_task(void *pvParameters) 127 | { 128 | uart_event_t event; 129 | size_t buffered_size; 130 | uint8_t* dtmp = (uint8_t*) malloc(RX_BUF_SIZE); 131 | UART_RXsem = xSemaphoreCreateCounting( 10, 0 );; 132 | for(;;) 133 | { 134 | //Waiting for UART event. 135 | if(xQueueReceive(uartRx_queue, (void * )&event, portMAX_DELAY)) 136 | { 137 | bzero(dtmp, RX_BUF_SIZE); 138 | 139 | switch(event.type) 140 | { 141 | //Event of UART receving data 142 | case UART_DATA: 143 | // ESP_LOGI(UART_DEBUG, "%d", event.size); 144 | uart_read_bytes(UART_AT_PORT, hUart.uart_rxBuffer, event.size, portMAX_DELAY); 145 | 146 | hUart.uart_rxPacketSize = event.size; 147 | 148 | hUart.uart_status.flags.rxPacket = 1; 149 | 150 | xQueueSendToBack(uartRxStore_queue, &hUart, portMAX_DELAY); 151 | 152 | // xSemaphoreGive(UART_RXsem); 153 | 154 | // memset(&hUart, 0, sizeof(uartHandler_t)); 155 | break; 156 | //Event of HW FIFO overflow detected 157 | case UART_FIFO_OVF: 158 | ESP_LOGI(UART_DEBUG, "hw fifo overflow"); 159 | // If fifo overflow happened, you should consider adding flow control for your application. 160 | // The ISR has already reset the rx FIFO, 161 | // As an example, we directly flush the rx buffer here in order to read more data. 162 | uart_flush_input(UART_AT_PORT); 163 | xQueueReset(uartRx_queue); 164 | break; 165 | //Event of UART ring buffer full 166 | case UART_BUFFER_FULL: 167 | ESP_LOGI(UART_DEBUG, "ring buffer full"); 168 | // If buffer full happened, you should consider encreasing your buffer size 169 | // As an example, we directly flush the rx buffer here in order to read more data. 170 | uart_flush_input(UART_AT_PORT); 171 | xQueueReset(uartRx_queue); 172 | break; 173 | 174 | //UART_PATTERN_DET 175 | case UART_PATTERN_DET: 176 | uart_get_buffered_data_len(UART_AT_PORT, &buffered_size); 177 | int pos = uart_pattern_pop_pos(UART_AT_PORT); 178 | ESP_LOGI(UART_DEBUG, "[UART PATTERN DETECTED] pos: %d, buffered size: %d", pos, buffered_size); 179 | if (pos == -1) { 180 | // There used to be a UART_PATTERN_DET event, but the pattern position queue is full so that it can not 181 | // record the position. We should set a larger queue size. 182 | // As an example, we directly flush the rx buffer here. 183 | uart_flush_input(UART_AT_PORT); 184 | } else { 185 | uart_read_bytes(UART_AT_PORT, dtmp, pos, 100 / portTICK_PERIOD_MS); 186 | uint8_t pat[PATTERN_AT_COUNT + 1]; 187 | memset(pat, 0, sizeof(pat)); 188 | uart_read_bytes(UART_AT_PORT, pat, PATTERN_AT_COUNT, 100 / portTICK_PERIOD_MS); 189 | ESP_LOGI(UART_DEBUG, "read data: %s", dtmp); 190 | ESP_LOGI(UART_DEBUG, "read pat : %s", pat); 191 | } 192 | break; 193 | //Others 194 | default: 195 | ESP_LOGI(UART_DEBUG, "uart event type: %d", event.type); 196 | break; 197 | } 198 | } 199 | } 200 | free(dtmp); 201 | dtmp = NULL; 202 | vTaskDelete(NULL); 203 | } 204 | 205 | /************************** Useful Electronics ****************END OF FILE***/ 206 | -------------------------------------------------------------------------------- /main/uart_config.h: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | ****************************************************************************** 4 | * @Channel Link : https://www.youtube.com/user/wardzx1 5 | * @file : uart.h 6 | * @author : Ward Almasarani - Useful Electronics 7 | * @version : v.1.0 8 | * @date : Sep 5, 2022 9 | * @brief : 10 | * 11 | ******************************************************************************/ 12 | 13 | #ifndef MAIN_UART_CONFIG_H_ 14 | #define MAIN_UART_CONFIG_H_ 15 | 16 | 17 | /* INCLUDES ------------------------------------------------------------------*/ 18 | #include 19 | #include 20 | #include "freertos/FreeRTOS.h" 21 | #include "freertos/task.h" 22 | #include "freertos/queue.h" 23 | #include "esp_log.h" 24 | #include "driver/uart.h" 25 | #include "driver/gpio.h" 26 | /* MACROS --------------------------------------------------------------------*/ 27 | #define TXD_PIN (GPIO_NUM_10) 28 | #define RXD_PIN (GPIO_NUM_9) 29 | 30 | #define UART_AT_PORT UART_NUM_1 31 | #define PATTERN_AT_COUNT 2 32 | 33 | #define RX_BUF_SIZE 1024 34 | #define TX_BUF_SIZE 1024 35 | 36 | 37 | /* ENUMORATIONS --------------------------------------------------------------*/ 38 | 39 | /* STRUCTURES & TYPEDEFS -----------------------------------------------------*/ 40 | typedef struct 41 | { 42 | uint8_t uart_rxBuffer[RX_BUF_SIZE]; 43 | uint8_t uart_txBuffer[TX_BUF_SIZE]; 44 | uint8_t uart_rxPacketSize; 45 | uint8_t uart_txPacketSize; 46 | union 47 | { 48 | uint8_t all; 49 | struct 50 | { 51 | uint8_t reserved :7, 52 | rxPacket :1; 53 | }flags; 54 | }uart_status; 55 | }uartHandler_t; 56 | /* VARIABLES -----------------------------------------------------------------*/ 57 | extern QueueHandle_t uartRxStore_queue; 58 | extern SemaphoreHandle_t UART_RXsem; 59 | extern QueueHandle_t uartTx_queue; 60 | extern uartHandler_t hUart; 61 | /* FUNCTIONS DECLARATION -----------------------------------------------------*/ 62 | void uartBufferInit (void); 63 | uint8_t uartGetRxBuffer (uint8_t* buffer); 64 | uint8_t uartCheckPacketRxFlag (void); 65 | void uartResetPacketRxFlag (void); 66 | void uart_config (void); 67 | void uart_event_task (void *pvParameters); 68 | void uart_transmission_task (void *pvParameters); 69 | 70 | 71 | #endif /* MAIN_UART_CONFIG_H_ */ 72 | 73 | /************************** Useful Electronics ****************END OF FILE***/ 74 | -------------------------------------------------------------------------------- /main/wireless/mqtt.c: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * (c) Copyright 2012-2023; USEFUL ELECTRONICS 4 | * 5 | * All rights reserved. Protected by international copyright laws. 6 | * Knowledge of the source code may not be used to write a similar 7 | * product. This file may only be used in accordance with a license 8 | * and should not be redistributed in any way. 9 | * 10 | *****************************************************************************/ 11 | 12 | /** 13 | ****************************************************************************** 14 | * @Channel Link : https://www.youtube.com/user/wardzx1 15 | * @file : mqtt.c 16 | * @author : Ward Almasarani 17 | * @version : v.1.0 18 | * @date : Jan 2, 2023 19 | * @brief : 20 | * 21 | ******************************************************************************/ 22 | 23 | 24 | /* INCLUDES ------------------------------------------------------------------*/ 25 | #include "mqtt.h" 26 | 27 | /* PRIVATE STRUCTRES ---------------------------------------------------------*/ 28 | 29 | /* VARIABLES -----------------------------------------------------------------*/ 30 | static const char *TAG = "MQTT"; 31 | 32 | QueueHandle_t mqttSubscribe_queue; 33 | 34 | mqtt_buffer_t mqttSubscribeBuffer; 35 | 36 | static esp_mqtt_client_handle_t mqttClient = {0}; 37 | static esp_mqtt_client_config_t mqtt_cfg = {0}; 38 | /* DEFINITIONS ---------------------------------------------------------------*/ 39 | 40 | /* MACROS --------------------------------------------------------------------*/ 41 | 42 | /* PRIVATE FUNCTIONS DECLARATION ---------------------------------------------*/ 43 | static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data); 44 | /* FUNCTION PROTOTYPES -------------------------------------------------------*/ 45 | /** 46 | * @brief Event handler registered to receive MQTT events 47 | * 48 | * This function is called by the MQTT client event loop. 49 | * 50 | * @param handler_args user data registered to the event. 51 | * 52 | * @param base Event base for the handler(always MQTT Base in this example). 53 | * 54 | * @param event_id The id for the received event. 55 | * 56 | * @param event_data The data for the event, esp_mqtt_event_handle_t. 57 | */ 58 | static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) 59 | { 60 | ESP_LOGI(TAG, "Event dispatched from event loop base=%s, event_id=%d", base, (int)event_id); 61 | esp_mqtt_event_handle_t event = event_data; 62 | esp_mqtt_client_handle_t client = event->client; 63 | int msg = 0; 64 | switch ((esp_mqtt_event_id_t)event_id) 65 | { 66 | case MQTT_EVENT_CONNECTED: 67 | ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED"); 68 | //Topics subscription is done after successful broker connection callback 69 | mqttSubscribeBuffer.eventType = MQTT_BROKER_CONNECT; 70 | 71 | xQueueSendToBack(mqttSubscribe_queue, (void *)&mqttSubscribeBuffer, portMAX_DELAY); 72 | 73 | esp_mqtt_client_subscribe(client, MQTT_LAMP_GETON, 0); 74 | 75 | esp_mqtt_client_subscribe(client, MQTT_LAMP_GETHSV, 0); 76 | break; 77 | case MQTT_EVENT_DISCONNECTED: 78 | ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED"); 79 | 80 | mqttSubscribeBuffer.eventType = MQTT_BROKER_DISCONNECT; 81 | 82 | xQueueSendToBack(mqttSubscribe_queue, (void *)&mqttSubscribeBuffer, portMAX_DELAY); 83 | 84 | break; 85 | 86 | case MQTT_EVENT_SUBSCRIBED: 87 | ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id); 88 | 89 | ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg); 90 | break; 91 | case MQTT_EVENT_UNSUBSCRIBED: 92 | ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id); 93 | break; 94 | case MQTT_EVENT_PUBLISHED: 95 | ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id); 96 | break; 97 | case MQTT_EVENT_DATA: 98 | ESP_LOGI(TAG, "MQTT_EVENT_DATA"); 99 | 100 | printf("TOPIC=%.*s\r\n", event->topic_len, event->topic); 101 | 102 | printf("DATA=%.*s\r\n", event->data_len, event->data); 103 | 104 | 105 | mqttSubscribeBuffer.msgLength = event->data_len; 106 | 107 | strcpy(mqttSubscribeBuffer.topicString ,event->topic); 108 | 109 | memcpy(mqttSubscribeBuffer.data, event->data, event->data_len); 110 | 111 | mqttSubscribeBuffer.eventType = MQTT_TOPIC_DATA_RX; 112 | 113 | xQueueSendToBack(mqttSubscribe_queue, (void *)&mqttSubscribeBuffer, portMAX_DELAY); 114 | 115 | 116 | 117 | 118 | break; 119 | case MQTT_EVENT_ERROR: 120 | ESP_LOGI(TAG, "MQTT_EVENT_ERROR"); 121 | 122 | break; 123 | default: 124 | ESP_LOGI(TAG, "Other event id:%d", event->event_id); 125 | break; 126 | } 127 | //Clear MQTT buffer 128 | memset(&mqttSubscribeBuffer, 0, sizeof(mqtt_buffer_t)); 129 | } 130 | /** 131 | * @brief Publish data to a specific topic over MQTT 132 | * 133 | * @param topic : to publish data to 134 | * 135 | * @param data : pointer to the data to be sent 136 | * 137 | * @param len : number of bytes to be sent over publish request 138 | */ 139 | void mqtt_publish(const char *topic, const char *data, int len) 140 | { 141 | const uint8_t quelityOfServiceLevel = 0; 142 | const uint8_t retainFeature = false; 143 | 144 | esp_mqtt_client_publish(mqttClient, topic, data, len, (int) quelityOfServiceLevel, (int) retainFeature); 145 | } 146 | /** 147 | * @brief Start MQTT broker connection and register MQTT related events callback 148 | * 149 | */ 150 | void mqtt_app_start(void) 151 | { 152 | mqtt_cfg.broker.address.uri = MQTT_BROKER_URI, 153 | mqtt_cfg.credentials.client_id = MQTT_CLIENT_ID, 154 | 155 | mqttSubscribe_queue = xQueueCreate(10, sizeof(mqtt_buffer_t)); 156 | 157 | memset(&mqttSubscribeBuffer, 0, sizeof(mqtt_buffer_t)); 158 | 159 | esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg); 160 | 161 | memcpy(&mqttClient, &client, sizeof(esp_mqtt_client_handle_t)); 162 | /* The last argument may be used to pass data to the event handler, in this example mqtt_event_handler */ 163 | esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL); 164 | 165 | esp_mqtt_client_start(client); 166 | 167 | 168 | } 169 | 170 | /************************** Useful Electronics ****************END OF FILE***/ 171 | -------------------------------------------------------------------------------- /main/wireless/mqtt.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * (c) Copyright 2012-2023; USEFUL ELECTRONICS 4 | * 5 | * All rights reserved. Protected by international copyright laws. 6 | * Knowledge of the source code may not be used to write a similar 7 | * product. This file may only be used in accordance with a license 8 | * and should not be redistributed in any way. 9 | * 10 | *****************************************************************************/ 11 | 12 | /** 13 | ****************************************************************************** 14 | * @Channel Link : https://www.youtube.com/user/wardzx1 15 | * @file : mqtt.h 16 | * @author : Ward Almasarani 17 | * @version : v.1.0 18 | * @date : Jan 2, 2023 19 | * @brief : 20 | * 21 | ******************************************************************************/ 22 | 23 | #ifndef MAIN_MQTT_H_ 24 | #define MAIN_MQTT_H_ 25 | 26 | 27 | /* INCLUDES ------------------------------------------------------------------*/ 28 | #include "string.h" 29 | #include "esp_log.h" 30 | #include "mqtt_client.h" 31 | /* PRIVATE STRUCTRES ---------------------------------------------------------*/ 32 | 33 | /* VARIABLES -----------------------------------------------------------------*/ 34 | extern QueueHandle_t mqttSubscribe_queue; 35 | /* DEFINITIONS ---------------------------------------------------------------*/ 36 | 37 | /* MACROS --------------------------------------------------------------------*/ 38 | #define MQTT_MAX_TOPIC_LENGTH 30 39 | #define MQTT_MAX_DATA_LENGTH 30 40 | 41 | #define MQTT_COLOR_TOPIC "lampColor" 42 | #define MQTT_MODE_TOPIC "lampMode" 43 | #define MQTT_SWITCH_TOPIC "switch" 44 | #define MQTT_FREQUENCY_TOPIC "lampFreq" 45 | #define MQTT_REQUEST_TOPIC "request" 46 | #define MQTT_TEMPERATURE_TOPIC "temperature" 47 | 48 | #define MQTT_LAMP_SETON "2/rgbled/seton" 49 | #define MQTT_LAMP_GETON "2/rgbled/geton" 50 | #define MQTT_LAMP_SETHSV "2/rgbled/sethsv" 51 | #define MQTT_LAMP_GETHSV "2/rgbled/gethsv" 52 | 53 | #define MQTT_BROKER_URI "mqtt://192.168.1.103:1883" 54 | #define MQTT_CLIENT_ID "Encoder" 55 | 56 | 57 | /* PRIVATE FUNCTIONS DECLARATION ---------------------------------------------*/ 58 | typedef enum 59 | { 60 | MQTT_BROKER_CONNECT = 0, 61 | MQTT_BROKER_DISCONNECT, 62 | MQTT_TOPIC_PUBLISHED, 63 | MQTT_TOPIC_DATA_RX 64 | }mqtt_event_t; 65 | typedef struct 66 | { 67 | char topicString[MQTT_MAX_TOPIC_LENGTH]; 68 | uint16_t msgLength; 69 | char data[MQTT_MAX_DATA_LENGTH]; 70 | mqtt_event_t eventType; 71 | }mqtt_buffer_t; 72 | /* FUNCTION PROTOTYPES -------------------------------------------------------*/ 73 | /** 74 | * @brief Start MQTT broker connection and register MQTT related events callback 75 | * 76 | */ 77 | void mqtt_app_start(void); 78 | 79 | void mqtt_publish(const char *topic, const char *data, int len); 80 | 81 | 82 | #endif /* MAIN_MQTT_H_ */ 83 | 84 | 85 | /************************** Useful Electronics ****************END OF FILE***/ 86 | -------------------------------------------------------------------------------- /main/wireless/sntp.c: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * USEFUL ELECTRONICS 4 | ******************************************************************************/ 5 | /** 6 | ****************************************************************************** 7 | * @file : sntp.c 8 | * @author : WARD ALMASARANI 9 | * @version : v.1.0 10 | * @date : Feb 15, 2023 11 | * @link : https://www.youtube.com/@usefulelectronics 12 | * Hold Ctrl button and click on the link to be directed to 13 | Useful Electronics YouTube channel 14 | ******************************************************************************/ 15 | 16 | 17 | /* INCLUDES ------------------------------------------------------------------*/ 18 | #include "sntp.h" 19 | //#include "esp_netif_sntp.h 20 | /* PRIVATE STRUCTRES ---------------------------------------------------------*/ 21 | 22 | /* VARIABLES -----------------------------------------------------------------*/ 23 | static const char *sntp = "sntp"; 24 | static time_t now; 25 | /* DEFINITIONS ---------------------------------------------------------------*/ 26 | 27 | /* MACROS --------------------------------------------------------------------*/ 28 | 29 | /* PRIVATE FUNCTIONS DECLARATION ---------------------------------------------*/ 30 | 31 | /* FUNCTION PROTOTYPES -------------------------------------------------------*/ 32 | void sntp_time_get(struct tm* timeinfo) 33 | { 34 | time(&now); 35 | 36 | localtime_r(&now, timeinfo); 37 | 38 | // sntp_set_sync_status(SNTP_SYNC_STATUS_COMPLETED); 39 | } 40 | 41 | void sntp_config(void) 42 | { 43 | int retry = 0; 44 | const int retry_count = 15; 45 | 46 | time(&now); 47 | 48 | // Set timezone to Turkey Standard Time 49 | setenv("TZ", "UTC-3", 1); 50 | tzset(); 51 | char buff[INET6_ADDRSTRLEN]; 52 | 53 | sntp_setoperatingmode(SNTP_OPMODE_POLL); 54 | sntp_setservername(0, "pool.ntp.org"); 55 | ip_addr_t const *ip = sntp_getserver(0); 56 | ipaddr_ntoa_r(ip, buff, INET6_ADDRSTRLEN); 57 | 58 | sntp_init(); 59 | 60 | 61 | 62 | } 63 | 64 | /*************************************** USEFUL ELECTRONICS*****END OF FILE****/ 65 | -------------------------------------------------------------------------------- /main/wireless/sntp.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * USEFUL ELECTRONICS 4 | ******************************************************************************/ 5 | /** 6 | ****************************************************************************** 7 | * @file : sntp.h 8 | * @author : WARD ALMASARANI 9 | * @version : v.1.0 10 | * @date : Feb 15, 2023 11 | * @link : https://www.youtube.com/@usefulelectronics 12 | * Hold Ctrl button and click on the link to be directed to 13 | Useful Electronics YouTube channel 14 | ******************************************************************************/ 15 | 16 | #ifndef MAIN_SNTP_H_ 17 | #define MAIN_SNTP_H_ 18 | 19 | 20 | /* INCLUDES ------------------------------------------------------------------*/ 21 | #include "time.h" 22 | #include "lwip/ip_addr.h" 23 | #include "lwip/sockets.h" 24 | #include "esp_sntp.h" 25 | #include "esp_log.h" 26 | /* MACROS --------------------------------------------------------------------*/ 27 | 28 | /* ENUMORATIONS --------------------------------------------------------------*/ 29 | 30 | /* STRUCTURES & TYPEDEFS -----------------------------------------------------*/ 31 | 32 | /* VARIABLES -----------------------------------------------------------------*/ 33 | 34 | /* FUNCTIONS DECLARATION -----------------------------------------------------*/ 35 | void sntp_time_get(struct tm* timeinfo); 36 | void sntp_config(void); 37 | 38 | 39 | #endif /* MAIN_SNTP_H_ */ 40 | 41 | /*************************************** USEFUL ELECTRONICS*****END OF FILE****/ 42 | -------------------------------------------------------------------------------- /main/wireless/wifi_connect.c: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * (c) Copyright 2012-2023; USEFUL ELECTRONICS 4 | * 5 | * All rights reserved. Protected by international copyright laws. 6 | * Knowledge of the source code may not be used to write a similar 7 | * product. This file may only be used in accordance with a license 8 | * and should not be redistributed in any way. 9 | * 10 | *****************************************************************************/ 11 | 12 | /** 13 | ****************************************************************************** 14 | * @Channel Link : https://www.youtube.com/user/wardzx1 15 | * @file : wifi_connect.c 16 | * @author : Ward Almasarani 17 | * @version : v.1.0 18 | * @date : Jan 2, 2023 19 | * @brief : 20 | * 21 | ******************************************************************************/ 22 | 23 | 24 | /* INCLUDES ------------------------------------------------------------------*/ 25 | #include "wifi_connect.h" 26 | #include 27 | 28 | /* PRIVATE STRUCTRES ---------------------------------------------------------*/ 29 | 30 | /* VARIABLES -----------------------------------------------------------------*/ 31 | static const char* TAG = "WiFi"; 32 | 33 | uint8_t wifi_memory[100] = {0}; 34 | /* DEFINITIONS ---------------------------------------------------------------*/ 35 | 36 | /* MACROS --------------------------------------------------------------------*/ 37 | 38 | /* PRIVATE FUNCTIONS DECLARATION ---------------------------------------------*/ 39 | 40 | /* FUNCTION PROTOTYPES -------------------------------------------------------*/ 41 | void wifi_connect(void) 42 | { 43 | ESP_ERROR_CHECK(nvs_flash_init()); 44 | ESP_ERROR_CHECK(esp_netif_init()); 45 | ESP_ERROR_CHECK(esp_event_loop_create_default()); 46 | 47 | /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig. 48 | * Read "Establishing Wi-Fi or Ethernet Connection" section in 49 | * examples/protocols/README.md for more information about this function. 50 | */ 51 | ESP_ERROR_CHECK(example_connect()); 52 | } 53 | 54 | bool wifi_is_connected(void) 55 | { 56 | wifi_ap_record_t ap_info; 57 | 58 | esp_err_t err = esp_wifi_sta_get_ap_info(&ap_info); 59 | 60 | if (err == ESP_OK) 61 | { 62 | return true; 63 | } 64 | else if (err == ESP_ERR_WIFI_NOT_CONNECT) 65 | { 66 | return false; 67 | } 68 | return false; 69 | } 70 | 71 | int8_t wifi_get_rssi(void) 72 | { 73 | wifi_ap_record_t ap_info; 74 | 75 | esp_wifi_sta_get_ap_info(&ap_info); 76 | 77 | return ap_info.rssi; 78 | } 79 | char* wifi_get_connection_ip(void) 80 | { 81 | // Get the default Wi-Fi station interface 82 | esp_netif_t *netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"); 83 | if (!netif) 84 | { 85 | return NULL; 86 | } 87 | // Retrieve the IP information 88 | esp_netif_ip_info_t ip_info; 89 | if (esp_netif_get_ip_info(netif, &ip_info) == ESP_OK) 90 | { 91 | if (ip_info.ip.addr) 92 | { 93 | // Clear wifi layer related memory 94 | memset(wifi_memory, 0, sizeof(wifi_memory)); 95 | // Format the IP as a string 96 | sprintf((char*)wifi_memory, IPSTR, IP2STR(&ip_info.ip)); 97 | 98 | return (char*)wifi_memory; 99 | 100 | } 101 | else 102 | { 103 | ESP_LOGI(TAG, "No IP address assigned yet"); 104 | } 105 | } 106 | else 107 | { 108 | ESP_LOGI(TAG, "Failed to get IP info"); 109 | } 110 | return NULL; 111 | } 112 | 113 | uint16_t wifi_scan_start(void) 114 | { 115 | // Configure the scan parameters 116 | wifi_scan_config_t scan_config = 117 | { 118 | .ssid = NULL, 119 | .bssid = NULL, 120 | .channel = 0, 121 | .show_hidden = true 122 | }; 123 | 124 | // Start the Wi-Fi scan 125 | ESP_ERROR_CHECK(esp_wifi_scan_start(&scan_config, true)); // Blocking scan 126 | ESP_LOGI(TAG, "Wi-Fi scan completed"); 127 | // Get the number of found APs 128 | uint16_t number = 0; 129 | ESP_ERROR_CHECK(esp_wifi_scan_get_ap_num(&number)); 130 | ESP_LOGI(TAG, "Found %d access points", number); 131 | 132 | return number; 133 | } 134 | 135 | char* wifi_scan_result(uint16_t number) 136 | { 137 | // Allocate memory to store AP records 138 | uint16_t access_point_index = number - 1; 139 | wifi_ap_record_t *ap_records = malloc(number * sizeof(wifi_ap_record_t)); 140 | if (ap_records == NULL) 141 | { 142 | ESP_LOGE(TAG, "Failed to allocate memory for AP records"); 143 | return NULL; 144 | } 145 | // Retrieve the scan results 146 | ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&number, ap_records)); 147 | 148 | // Log the scan results 149 | 150 | sprintf((char *)wifi_memory, "SSID: %s, RSSI: %d, Channel: %d", 151 | ap_records[access_point_index].ssid, ap_records[access_point_index].rssi, ap_records[access_point_index].primary); 152 | 153 | ESP_LOGI(TAG, "SSID: %s, RSSI: %d, Channel: %d", 154 | ap_records[access_point_index].ssid, ap_records[access_point_index].rssi, ap_records[access_point_index].primary); 155 | 156 | 157 | // Free allocated memory 158 | free(ap_records); 159 | 160 | return (char*) wifi_memory; 161 | } 162 | /************************** Useful Electronics ****************END OF FILE***/ 163 | -------------------------------------------------------------------------------- /main/wireless/wifi_connect.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * (c) Copyright 2012-2023; USEFUL ELECTRONICS 4 | * 5 | * All rights reserved. Protected by international copyright laws. 6 | * Knowledge of the source code may not be used to write a similar 7 | * product. This file may only be used in accordance with a license 8 | * and should not be redistributed in any way. 9 | * 10 | *****************************************************************************/ 11 | 12 | /** 13 | ****************************************************************************** 14 | * @Channel Link : https://www.youtube.com/user/wardzx1 15 | * @file : wifi_connect.h 16 | * @author : Ward Almasarani 17 | * @version : v.1.0 18 | * @date : Jan 2, 2023 19 | * @brief : 20 | * 21 | ******************************************************************************/ 22 | 23 | #ifndef MAIN_WIFI_CONNECT_H_ 24 | #define MAIN_WIFI_CONNECT_H_ 25 | 26 | 27 | /* INCLUDES ------------------------------------------------------------------*/ 28 | #include "esp_wifi.h" 29 | #include "esp_system.h" 30 | #include "nvs_flash.h" 31 | #include "esp_event.h" 32 | #include "esp_netif.h" 33 | #include "protocol_examples_common.h" 34 | 35 | #include "lwip/sockets.h" 36 | #include "lwip/dns.h" 37 | #include "lwip/netdb.h" 38 | 39 | #include "esp_log.h" 40 | #include "stdbool.h" 41 | #include 42 | /* PRIVATE STRUCTRES ---------------------------------------------------------*/ 43 | 44 | /* VARIABLES -----------------------------------------------------------------*/ 45 | 46 | /* DEFINITIONS ---------------------------------------------------------------*/ 47 | 48 | /* MACROS --------------------------------------------------------------------*/ 49 | 50 | /* PRIVATE FUNCTIONS DECLARATION ---------------------------------------------*/ 51 | 52 | /* FUNCTION PROTOTYPES -------------------------------------------------------*/ 53 | 54 | /** 55 | * @brief Initialize and connect the ESP32 to a Wi-Fi network. 56 | * 57 | * This function initializes the necessary components for Wi-Fi connectivity, 58 | * including the Non-Volatile Storage (NVS), network interfaces, and event loop. 59 | * It also establishes a connection to the configured Wi-Fi network using the 60 | * `example_connect()` helper function provided by ESP-IDF. 61 | * 62 | * @note Ensure that the Wi-Fi credentials are configured in `menuconfig` or 63 | * provided through the `example_connect()` implementation. 64 | * 65 | * @attention This function uses blocking calls and may halt execution 66 | * if the configuration or connection process fails. 67 | */ 68 | void wifi_connect(void); 69 | /** 70 | * @brief Get the IP address of the current Wi-Fi connection as a string. 71 | * 72 | * This function retrieves the IP address of the ESP32 when it is connected 73 | * to a Wi-Fi network. The IP address is returned as a null-terminated string. 74 | * 75 | * The memory for the IP address string is managed internally and must not 76 | * be modified by the caller. If no IP address is assigned or the ESP32 is not 77 | * connected to a Wi-Fi network, the function returns `NULL`. 78 | * 79 | * @note Ensure that Wi-Fi is initialized and connected before calling this function. 80 | * 81 | * @return 82 | * - A pointer to a statically allocated string containing the IP address on success. 83 | * - `NULL` if the IP address cannot be retrieved. 84 | * 85 | */ 86 | char* wifi_get_connection_ip(void); 87 | /** 88 | * @brief Get the current Wi-Fi connection's RSSI (signal strength). 89 | * 90 | * This function retrieves the RSSI (Received Signal Strength Indicator) value 91 | * of the currently connected Wi-Fi access point. RSSI is measured in dBm. 92 | * 93 | * @note Ensure that the ESP32 is connected to a Wi-Fi network before calling this function. 94 | * 95 | * @return 96 | * - The RSSI value in dBm if successful. 97 | * - Returns undefined behavior if the ESP32 is not connected. 98 | */ 99 | int8_t wifi_get_rssi(void); 100 | #endif /* MAIN_WIFI_CONNECT_H_ */ 101 | 102 | 103 | /************************** Useful Electronics ****************END OF FILE***/ 104 | -------------------------------------------------------------------------------- /partitions.csv: -------------------------------------------------------------------------------- 1 | # Name, Type, SubType, Offset, Size, Flags 2 | # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap,,,, 3 | nvs,data, nvs,0x9000,0x4000, 4 | otadata,data,ota,0xd000,0x2000, 5 | phy_init, data, phy,0xf000, 0x1000, 6 | factory, app, factory,0x10000,2M, 7 | # storage,data, spiffs, ,0xF0000, 8 | --------------------------------------------------------------------------------