diff --git a/code/01.start/blink/.gitignore b/code/01.start/blink/.gitignore new file mode 100644 index 0000000..ee2dc29 --- /dev/null +++ b/code/01.start/blink/.gitignore @@ -0,0 +1,6 @@ +*build +*managed_components +dependencies.lock +sdkconfig +sdkconfig.old + diff --git a/code/01.start/blink/CMakeLists.txt b/code/01.start/blink/CMakeLists.txt new file mode 100644 index 0000000..489742a --- /dev/null +++ b/code/01.start/blink/CMakeLists.txt @@ -0,0 +1,6 @@ +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(blink) diff --git a/code/01.start/blink/README.md b/code/01.start/blink/README.md new file mode 100644 index 0000000..4ec579e --- /dev/null +++ b/code/01.start/blink/README.md @@ -0,0 +1,77 @@ +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | + +# Blink Example + +(See the README.md file in the upper level 'examples' directory for more information about examples.) + +This example demonstrates how to blink a LED using GPIO or using the [led_strip](https://components.espressif.com/component/espressif/led_strip) component for the addressable LED, i.e. [WS2812](https://cdn-shop.adafruit.com/datasheets/WS2812B.pdf). + +The `led_strip` is installed via [component manager](main/idf_component.yml). + +## How to Use Example + +Before project configuration and build, be sure to set the correct chip target using `idf.py set-target `. + +### Hardware Required + +* A development board with Espressif SoC (e.g., ESP32-DevKitC, ESP-WROVER-KIT, etc.) +* A USB cable for Power supply and programming + +Some development boards use an addressable LED instead of a regular one. These development boards include: + +| Board | LED type | Pin | +| -------------------- | -------------------- | -------------------- | +| ESP32-C3-DevKitC-1 | Addressable | GPIO8 | +| ESP32-C3-DevKitM-1 | Addressable | GPIO8 | +| ESP32-S2-DevKitM-1 | Addressable | GPIO18 | +| ESP32-S2-Saola-1 | Addressable | GPIO18 | +| ESP32-S3-DevKitC-1 | Addressable | GPIO48 | + +See [Development Boards](https://www.espressif.com/en/products/devkits) for more information about it. + +### Configure the Project + +Open the project configuration menu (`idf.py menuconfig`). + +In the `Example Configuration` menu: + +* Select the LED type in the `Blink LED type` option. + * Use `GPIO` for regular LED blink. +* Set the GPIO number used for the signal in the `Blink GPIO number` option. +* Set the blinking period in the `Blink period in ms` option. + +### Build and Flash + +Run `idf.py -p PORT flash monitor` to build, flash and monitor the project. + +(To exit the serial monitor, type ``Ctrl-]``.) + +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. + +## Example Output + +As you run the example, you will see the LED blinking, according to the previously defined period. For the addressable LED, you can also change the LED color by setting the `led_strip_set_pixel(led_strip, 0, 16, 16, 16);` (LED Strip, Pixel Number, Red, Green, Blue) with values from 0 to 255 in the [source file](main/blink_example_main.c). + +```text +I (315) example: Example configured to blink addressable LED! +I (325) example: Turning the LED OFF! +I (1325) example: Turning the LED ON! +I (2325) example: Turning the LED OFF! +I (3325) example: Turning the LED ON! +I (4325) example: Turning the LED OFF! +I (5325) example: Turning the LED ON! +I (6325) example: Turning the LED OFF! +I (7325) example: Turning the LED ON! +I (8325) example: Turning the LED OFF! +``` + +Note: The color order could be different according to the LED model. + +The pixel number indicates the pixel position in the LED strip. For a single LED, use 0. + +## Troubleshooting + +* If the LED isn't blinking, check the GPIO or the LED type selection in the `Example Configuration` menu. + +For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon. diff --git a/code/01.start/blink/main/CMakeLists.txt b/code/01.start/blink/main/CMakeLists.txt new file mode 100644 index 0000000..a7f0bac --- /dev/null +++ b/code/01.start/blink/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "blink_example_main.c" + INCLUDE_DIRS ".") diff --git a/code/01.start/blink/main/blink_example_main.c b/code/01.start/blink/main/blink_example_main.c new file mode 100644 index 0000000..8a7c4ed --- /dev/null +++ b/code/01.start/blink/main/blink_example_main.c @@ -0,0 +1,91 @@ +/* Blink Example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "driver/gpio.h" +#include "esp_log.h" +#include "led_strip.h" +#include "sdkconfig.h" + +static const char *TAG = "example"; + +/* Use project configuration menu (idf.py menuconfig) to choose the GPIO to blink, + or you can edit the following line and set a number here. +*/ +#define BLINK_GPIO CONFIG_BLINK_GPIO + +static uint8_t s_led_state = 0; + +#ifdef CONFIG_BLINK_LED_RMT + +static led_strip_handle_t led_strip; + +static void blink_led(void) +{ + /* If the addressable LED is enabled */ + if (s_led_state) { + /* Set the LED pixel using RGB from 0 (0%) to 255 (100%) for each color */ + led_strip_set_pixel(led_strip, 0, 16, 16, 16); + /* Refresh the strip to send data */ + led_strip_refresh(led_strip); + } else { + /* Set all LED off to clear all pixels */ + led_strip_clear(led_strip); + } +} + +static void configure_led(void) +{ + ESP_LOGI(TAG, "Example configured to blink addressable LED!"); + /* LED strip initialization with the GPIO and pixels number*/ + led_strip_config_t strip_config = { + .strip_gpio_num = BLINK_GPIO, + .max_leds = 1, // at least one LED on board + }; + led_strip_rmt_config_t rmt_config = { + .resolution_hz = 10 * 1000 * 1000, // 10MHz + }; + ESP_ERROR_CHECK(led_strip_new_rmt_device(&strip_config, &rmt_config, &led_strip)); + /* Set all LED off to clear all pixels */ + led_strip_clear(led_strip); +} + +#elif CONFIG_BLINK_LED_GPIO + +static void blink_led(void) +{ + /* Set the GPIO level according to the state (LOW or HIGH)*/ + gpio_set_level(BLINK_GPIO, s_led_state); +} + +static void configure_led(void) +{ + ESP_LOGI(TAG, "Example configured to blink GPIO LED!"); + gpio_reset_pin(BLINK_GPIO); + /* Set the GPIO as a push/pull output */ + gpio_set_direction(BLINK_GPIO, GPIO_MODE_OUTPUT); +} + +#endif + +void app_main(void) +{ + + /* Configure the peripheral according to the LED type */ + configure_led(); + + while (1) { + ESP_LOGI(TAG, "Turning the LED %s!", s_led_state == true ? "ON" : "OFF"); + blink_led(); + /* Toggle the LED state */ + s_led_state = !s_led_state; + vTaskDelay(CONFIG_BLINK_PERIOD / portTICK_PERIOD_MS); + } +} diff --git a/code/01.start/blink/main/idf_component.yml b/code/01.start/blink/main/idf_component.yml new file mode 100644 index 0000000..234f978 --- /dev/null +++ b/code/01.start/blink/main/idf_component.yml @@ -0,0 +1,2 @@ +dependencies: + espressif/led_strip: "^2.0.0" diff --git a/code/01.start/blink/pytest_blink.py b/code/01.start/blink/pytest_blink.py new file mode 100644 index 0000000..b7ea802 --- /dev/null +++ b/code/01.start/blink/pytest_blink.py @@ -0,0 +1,17 @@ +# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: CC0-1.0 + +import logging +import os + +import pytest +from pytest_embedded_idf.dut import IdfDut + + +@pytest.mark.supported_targets +@pytest.mark.generic +def test_blink(dut: IdfDut) -> None: + # check and log bin size + binary_file = os.path.join(dut.app.binary_path, 'blink.bin') + bin_size = os.path.getsize(binary_file) + logging.info('blink_bin_size : {}KB'.format(bin_size // 1024)) diff --git a/code/03.freertos_basic/task/任务优先级/CMakeLists.txt b/code/03.freertos_basic/task/任务优先级/CMakeLists.txt new file mode 100644 index 0000000..664d458 --- /dev/null +++ b/code/03.freertos_basic/task/任务优先级/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(main) diff --git a/code/03.freertos_basic/task/任务优先级/main/CMakeLists.txt b/code/03.freertos_basic/task/任务优先级/main/CMakeLists.txt new file mode 100644 index 0000000..f3e5917 --- /dev/null +++ b/code/03.freertos_basic/task/任务优先级/main/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") + +# target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format") diff --git a/code/03.freertos_basic/task/任务优先级/main/main.c b/code/03.freertos_basic/task/任务优先级/main/main.c new file mode 100644 index 0000000..772b0bc --- /dev/null +++ b/code/03.freertos_basic/task/任务优先级/main/main.c @@ -0,0 +1,42 @@ +#include +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +static const char *TAG = "main"; + +void Task_1(void *pvParameters) +{ + for (;;) + { + vTaskDelay(1000 / portTICK_PERIOD_MS); + ESP_LOGI(TAG, "Task_1"); + } + vTaskDelete(NULL); +} + +void Task_2(void *pvParameters) +{ + for (;;) + { + vTaskDelay(1000 / portTICK_PERIOD_MS); + ESP_LOGI(TAG, "Task_2"); + } + vTaskDelete(NULL); +} + +void app_main(void) +{ + UBaseType_t taskPriority_1 = 0; + UBaseType_t taskPriority_2 = 0; + TaskHandle_t taskHandle_1 = NULL; + TaskHandle_t taskHandle_2 = NULL; + + xTaskCreate(Task_1, "Task_1", 2048, NULL, 12, &taskHandle_1); + taskPriority_1 = uxTaskPriorityGet(taskHandle_1); + ESP_LOGI(TAG, "Task_1 优先级:%d", taskPriority_1); + + xTaskCreate(Task_2, "Task_1", 2048, NULL, 12, &taskHandle_2); + taskPriority_2 = uxTaskPriorityGet(taskHandle_2); + ESP_LOGI(TAG, "Task_1 优先级:%d", taskPriority_2); +} diff --git a/code/03.freertos_basic/task/任务优先级/sdkconfig.defaults b/code/03.freertos_basic/task/任务优先级/sdkconfig.defaults new file mode 100644 index 0000000..0f4b284 --- /dev/null +++ b/code/03.freertos_basic/task/任务优先级/sdkconfig.defaults @@ -0,0 +1,5 @@ +# This file was generated using idf.py save-defconfig. It can be edited manually. +# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration +# +CONFIG_IDF_TARGET="esp32s3" +CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y diff --git a/code/03.freertos_basic/task/任务列表信息显示/CMakeLists.txt b/code/03.freertos_basic/task/任务列表信息显示/CMakeLists.txt new file mode 100644 index 0000000..664d458 --- /dev/null +++ b/code/03.freertos_basic/task/任务列表信息显示/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(main) diff --git a/code/03.freertos_basic/task/任务列表信息显示/main/CMakeLists.txt b/code/03.freertos_basic/task/任务列表信息显示/main/CMakeLists.txt new file mode 100644 index 0000000..f3e5917 --- /dev/null +++ b/code/03.freertos_basic/task/任务列表信息显示/main/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") + +# target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format") diff --git a/code/03.freertos_basic/task/任务列表信息显示/main/main.c b/code/03.freertos_basic/task/任务列表信息显示/main/main.c new file mode 100644 index 0000000..0d26525 --- /dev/null +++ b/code/03.freertos_basic/task/任务列表信息显示/main/main.c @@ -0,0 +1,41 @@ +#include +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +static const char *TAG = "main"; + +void Task_1(void *pvParameters) +{ + for (;;) + { + vTaskDelay(1000 / portTICK_PERIOD_MS); + ESP_LOGI(TAG, "Task_1"); + } + vTaskDelete(NULL); +} + +void Task_2(void *pvParameters) +{ + for (;;) + { + vTaskDelay(1000 / portTICK_PERIOD_MS); + ESP_LOGI(TAG, "Task_2"); + } + vTaskDelete(NULL); +} + +void app_main(void) +{ + TaskHandle_t taskHandle_1 = NULL; + TaskHandle_t taskHandle_2 = NULL; + + xTaskCreate(Task_1, "Task_1", 2048, NULL, 12, &taskHandle_1); + xTaskCreate(Task_2, "Task_1", 2048, NULL, 12, &taskHandle_2); + + + // 输出任务列表 + static char cBuffer[512]={0}; + vTaskList(cBuffer); + ESP_LOGI(TAG, "任务列表:\n%s", cBuffer); +} diff --git a/code/03.freertos_basic/task/任务列表信息显示/sdkconfig.defaults b/code/03.freertos_basic/task/任务列表信息显示/sdkconfig.defaults new file mode 100644 index 0000000..cb398a7 --- /dev/null +++ b/code/03.freertos_basic/task/任务列表信息显示/sdkconfig.defaults @@ -0,0 +1,7 @@ +# This file was generated using idf.py save-defconfig. It can be edited manually. +# Espressif IoT Development Framework (ESP-IDF) 5.3.2 Project Minimal Configuration +# +CONFIG_IDF_TARGET="esp32s3" +CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y +CONFIG_FREERTOS_USE_TRACE_FACILITY=y +CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS=y diff --git a/code/03.freertos_basic/task/任务创建/CMakeLists.txt b/code/03.freertos_basic/task/任务创建/CMakeLists.txt new file mode 100644 index 0000000..664d458 --- /dev/null +++ b/code/03.freertos_basic/task/任务创建/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(main) diff --git a/code/03.freertos_basic/task/任务创建/main/CMakeLists.txt b/code/03.freertos_basic/task/任务创建/main/CMakeLists.txt new file mode 100644 index 0000000..cf2c455 --- /dev/null +++ b/code/03.freertos_basic/task/任务创建/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") diff --git a/code/03.freertos_basic/task/任务创建/main/main.c b/code/03.freertos_basic/task/任务创建/main/main.c new file mode 100644 index 0000000..8a0fcd8 --- /dev/null +++ b/code/03.freertos_basic/task/任务创建/main/main.c @@ -0,0 +1,29 @@ +#include +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +static const char *TAG = "main"; + +// 任务函数 +void myTask(void *pvParameters) +{ + for (;;) + { + vTaskDelay(1000 / portTICK_PERIOD_MS); + ESP_LOGI(TAG, "myTask"); + } +} + +void app_main(void) +{ + // 创建一个 FreeRTOS 任务 + // 参数说明: + // 1. 任务入口函数:myTask + // 2. 任务名称:"myTask",用于调试时标识任务 + // 3. 任务堆栈大小:2048 字节(适当分配以避免栈溢出) + // 4. 任务参数:NULL(未传递参数) + // 5. 任务优先级:1(优先级较低,空闲任务优先级为 0) + // 6. 任务句柄:NULL(不需要保存任务句柄) + xTaskCreate(myTask, "myTask", 2048, NULL, 1, NULL); +} diff --git a/code/03.freertos_basic/task/任务创建/sdkconfig.defaults b/code/03.freertos_basic/task/任务创建/sdkconfig.defaults new file mode 100644 index 0000000..0f4b284 --- /dev/null +++ b/code/03.freertos_basic/task/任务创建/sdkconfig.defaults @@ -0,0 +1,5 @@ +# This file was generated using idf.py save-defconfig. It can be edited manually. +# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration +# +CONFIG_IDF_TARGET="esp32s3" +CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y diff --git a/code/03.freertos_basic/task/任务创建时传递参数/CMakeLists.txt b/code/03.freertos_basic/task/任务创建时传递参数/CMakeLists.txt new file mode 100644 index 0000000..664d458 --- /dev/null +++ b/code/03.freertos_basic/task/任务创建时传递参数/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(main) diff --git a/code/03.freertos_basic/task/任务创建时传递参数/main/CMakeLists.txt b/code/03.freertos_basic/task/任务创建时传递参数/main/CMakeLists.txt new file mode 100644 index 0000000..f3e5917 --- /dev/null +++ b/code/03.freertos_basic/task/任务创建时传递参数/main/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") + +# target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format") diff --git a/code/03.freertos_basic/task/任务创建时传递参数/main/main.c b/code/03.freertos_basic/task/任务创建时传递参数/main/main.c new file mode 100644 index 0000000..bb53034 --- /dev/null +++ b/code/03.freertos_basic/task/任务创建时传递参数/main/main.c @@ -0,0 +1,64 @@ +#include +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +static const char *TAG = "main"; + +typedef struct +{ + int Int; + int Array[3]; +} MyStruct; + +// 任务函数1:接收整型参数 +void Task_1(void *pvParameters) +{ + int *pInt = (int *)pvParameters; + ESP_LOGI(TAG, "取得整型参数为:%d", *pInt); + vTaskDelete(NULL); +} + +// 任务函数2:接收数组参数 +void Task_2(void *pvParameters) +{ + int *pArray = (int *)pvParameters; + ESP_LOGI(TAG, "取得数组参数为:%d %d %d", *pArray, *(pArray + 1), *(pArray + 2)); + vTaskDelete(NULL); +} + +// 任务函数3:接收结构体参数 +void Task_3(void *pvParameters) +{ + MyStruct *pStruct = (MyStruct *)pvParameters; + ESP_LOGI(TAG, "取得结构体参数为:%d %d %d %d", pStruct->Int, pStruct->Array[0], pStruct->Array[1], pStruct->Array[2]); + vTaskDelete(NULL); +} + +// 任务函数4:接收字符串参数 +void Task_4(void *pvParameters) +{ + char *pChar = (char *)pvParameters; + ESP_LOGI(TAG, "取得字符串参数为:%s", pChar); + vTaskDelete(NULL); +} + +int Parameters_1 = 1; +int Parameters_2[3] = {1, 2, 3}; +MyStruct Parameters_3 = {1, {1, 2, 3}}; +static const char *Parameters_4 = "Hello World!"; + +void app_main(void) +{ + // 传递整形参数 + xTaskCreate(Task_1, "Task_1", 2048, (void *)&Parameters_1, 1, NULL); + + // 传递数组参数 + xTaskCreate(Task_2, "Task_2", 2048, (void *)&Parameters_2, 1, NULL); + + // 传递结构体参数 + xTaskCreate(Task_3, "Task_3", 3048, (void *)&Parameters_3, 1, NULL); + + // 传递字符串参数(注意这里没有取地址符号&) + xTaskCreate(Task_4, "Task_4", 3048, (void *)Parameters_4, 1, NULL); +} diff --git a/code/03.freertos_basic/task/任务创建时传递参数/sdkconfig.defaults b/code/03.freertos_basic/task/任务创建时传递参数/sdkconfig.defaults new file mode 100644 index 0000000..0f4b284 --- /dev/null +++ b/code/03.freertos_basic/task/任务创建时传递参数/sdkconfig.defaults @@ -0,0 +1,5 @@ +# This file was generated using idf.py save-defconfig. It can be edited manually. +# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration +# +CONFIG_IDF_TARGET="esp32s3" +CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y diff --git a/code/03.freertos_basic/task/任务删除_1/CMakeLists.txt b/code/03.freertos_basic/task/任务删除_1/CMakeLists.txt new file mode 100644 index 0000000..664d458 --- /dev/null +++ b/code/03.freertos_basic/task/任务删除_1/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(main) diff --git a/code/03.freertos_basic/task/任务删除_1/main/CMakeLists.txt b/code/03.freertos_basic/task/任务删除_1/main/CMakeLists.txt new file mode 100644 index 0000000..cf2c455 --- /dev/null +++ b/code/03.freertos_basic/task/任务删除_1/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") diff --git a/code/03.freertos_basic/task/任务删除_1/main/main.c b/code/03.freertos_basic/task/任务删除_1/main/main.c new file mode 100644 index 0000000..264e5a3 --- /dev/null +++ b/code/03.freertos_basic/task/任务删除_1/main/main.c @@ -0,0 +1,32 @@ +#include +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +static const char *TAG = "main"; + +// 任务函数 +void myTask(void *pvParameters) +{ + for (;;) + { + vTaskDelay(500 / portTICK_PERIOD_MS); + ESP_LOGI(TAG, "myTask"); + } +} + +void app_main(void) +{ + // 任务句柄 + TaskHandle_t taskHandle = NULL; + // 创建一个 FreeRTOS 任务 + xTaskCreate(myTask, "myTask", 2048, NULL, 1, &taskHandle); + + vTaskDelay(2000 / portTICK_PERIOD_MS); + + // 删除任务 + if (taskHandle != NULL) + { + vTaskDelete(taskHandle); + } +} diff --git a/code/03.freertos_basic/task/任务删除_1/sdkconfig.defaults b/code/03.freertos_basic/task/任务删除_1/sdkconfig.defaults new file mode 100644 index 0000000..0f4b284 --- /dev/null +++ b/code/03.freertos_basic/task/任务删除_1/sdkconfig.defaults @@ -0,0 +1,5 @@ +# This file was generated using idf.py save-defconfig. It can be edited manually. +# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration +# +CONFIG_IDF_TARGET="esp32s3" +CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y diff --git a/code/03.freertos_basic/task/任务删除_2/CMakeLists.txt b/code/03.freertos_basic/task/任务删除_2/CMakeLists.txt new file mode 100644 index 0000000..664d458 --- /dev/null +++ b/code/03.freertos_basic/task/任务删除_2/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(main) diff --git a/code/03.freertos_basic/task/任务删除_2/main/CMakeLists.txt b/code/03.freertos_basic/task/任务删除_2/main/CMakeLists.txt new file mode 100644 index 0000000..cf2c455 --- /dev/null +++ b/code/03.freertos_basic/task/任务删除_2/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") diff --git a/code/03.freertos_basic/task/任务删除_2/main/main.c b/code/03.freertos_basic/task/任务删除_2/main/main.c new file mode 100644 index 0000000..9fdbd2f --- /dev/null +++ b/code/03.freertos_basic/task/任务删除_2/main/main.c @@ -0,0 +1,28 @@ +#include +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +static const char *TAG = "main"; + +// 任务函数 +void myTask(void *pvParameters) +{ + vTaskDelay(1000 / portTICK_PERIOD_MS); + ESP_LOGI(TAG, "myTask:1"); + vTaskDelay(1000 / portTICK_PERIOD_MS); + ESP_LOGI(TAG, "myTask:2"); + vTaskDelay(1000 / portTICK_PERIOD_MS); + ESP_LOGI(TAG, "myTask:3"); + + // 删除任务(如果传递 NULL,则删除当前任务) + vTaskDelete(NULL); +} + +void app_main(void) +{ + // 任务句柄 + TaskHandle_t taskHandle = NULL; + // 创建一个 FreeRTOS 任务 + xTaskCreate(myTask, "myTask", 2048, NULL, 1, &taskHandle); +} diff --git a/code/03.freertos_basic/task/任务删除_2/sdkconfig.defaults b/code/03.freertos_basic/task/任务删除_2/sdkconfig.defaults new file mode 100644 index 0000000..0f4b284 --- /dev/null +++ b/code/03.freertos_basic/task/任务删除_2/sdkconfig.defaults @@ -0,0 +1,5 @@ +# This file was generated using idf.py save-defconfig. It can be edited manually. +# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration +# +CONFIG_IDF_TARGET="esp32s3" +CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y diff --git a/code/03.freertos_basic/timer/CMakeLists.txt b/code/03.freertos_basic/timer/CMakeLists.txt new file mode 100644 index 0000000..664d458 --- /dev/null +++ b/code/03.freertos_basic/timer/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(main) diff --git a/code/03.freertos_basic/timer/main/CMakeLists.txt b/code/03.freertos_basic/timer/main/CMakeLists.txt new file mode 100644 index 0000000..f3e5917 --- /dev/null +++ b/code/03.freertos_basic/timer/main/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") + +# target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format") diff --git a/code/03.freertos_basic/timer/main/main.c b/code/03.freertos_basic/timer/main/main.c new file mode 100644 index 0000000..77240a7 --- /dev/null +++ b/code/03.freertos_basic/timer/main/main.c @@ -0,0 +1,40 @@ +#include +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/timers.h" + +static const char *TAG = "main"; + +// 定时器回调 +void TimerCallback_1(TimerHandle_t xTimer) +{ + // 取到定时器的名字 + const char *timerName = pcTimerGetName(xTimer); + // 取得定时器的ID + void *timerID = pvTimerGetTimerID(xTimer); + ESP_LOGI(TAG, "定时器名称:%s,定时器id:%d,定时器回调函数执行", timerName, (int)timerID); +} + +void app_main(void) +{ + // 创建定时器句柄 + TimerHandle_t xTimer_1; + TimerHandle_t xTimer_2; + xTimer_1 = xTimerCreate("timer1", pdMS_TO_TICKS(1000), pdTRUE, (void *)0, TimerCallback_1); + xTimer_2 = xTimerCreate("timer2", pdMS_TO_TICKS(2000), pdTRUE, (void *)1, TimerCallback_1); + + xTimerStart(xTimer_1, 0); // 启动定时器 + xTimerStart(xTimer_2, 0); // 启动定时器 + + vTaskDelay(pdMS_TO_TICKS(5000)); + //停止定时器 + xTimerStop(xTimer_1, 0); + xTimerStop(xTimer_2, 0); +} + + +// 其他常用函数 +// xTimerChangePeriod():修改定时器周期 +// xTimerReset():重置定时器 +// xTimerDelete():删除定时器 diff --git a/code/03.freertos_basic/timer/sdkconfig.defaults b/code/03.freertos_basic/timer/sdkconfig.defaults new file mode 100644 index 0000000..cb398a7 --- /dev/null +++ b/code/03.freertos_basic/timer/sdkconfig.defaults @@ -0,0 +1,7 @@ +# This file was generated using idf.py save-defconfig. It can be edited manually. +# Espressif IoT Development Framework (ESP-IDF) 5.3.2 Project Minimal Configuration +# +CONFIG_IDF_TARGET="esp32s3" +CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y +CONFIG_FREERTOS_USE_TRACE_FACILITY=y +CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS=y diff --git a/code/03.freertos_basic/watchdog/readme.md b/code/03.freertos_basic/watchdog/readme.md new file mode 100644 index 0000000..e69de29 diff --git a/code/04.peripheral/basics/adc_continuous/.gitignore b/code/04.peripheral/basics/adc_continuous/.gitignore new file mode 100644 index 0000000..8da877b --- /dev/null +++ b/code/04.peripheral/basics/adc_continuous/.gitignore @@ -0,0 +1,6 @@ +build +*managed_components +dependencies.lock +sdkconfig +sdkconfig.old + diff --git a/code/04.peripheral/basics/adc_continuous/CMakeLists.txt b/code/04.peripheral/basics/adc_continuous/CMakeLists.txt new file mode 100644 index 0000000..57308d1 --- /dev/null +++ b/code/04.peripheral/basics/adc_continuous/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(adc_continuous) diff --git a/code/04.peripheral/basics/adc_continuous/main/CMakeLists.txt b/code/04.peripheral/basics/adc_continuous/main/CMakeLists.txt new file mode 100644 index 0000000..f63caba --- /dev/null +++ b/code/04.peripheral/basics/adc_continuous/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "adc_continuous.c" + INCLUDE_DIRS ".") diff --git a/code/04.peripheral/basics/adc_continuous/main/adc_continuous.c b/code/04.peripheral/basics/adc_continuous/main/adc_continuous.c new file mode 100644 index 0000000..99fc21f --- /dev/null +++ b/code/04.peripheral/basics/adc_continuous/main/adc_continuous.c @@ -0,0 +1,165 @@ +#include +#include +#include "sdkconfig.h" +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "esp_adc/adc_continuous.h" + +#define _EXAMPLE_ADC_UNIT_STR(unit) #unit +// C预处理器的字符串化操作符 #,它可以将宏参数转换为字符串常量。如果传递 ADC_UNIT 给 _EXAMPLE_ADC_UNIT_STR,它会生成字符串 "ADC_UNIT"。 +#define EXAMPLE_ADC_UNIT_STR(unit) _EXAMPLE_ADC_UNIT_STR(unit) +// 宏嵌套 + +// 用于从 adc_digi_output_data_t 结构体中提取通道号和数据值。 +#define EXAMPLE_ADC_GET_CHANNEL(p_data) ((p_data)->type1.channel) +#define EXAMPLE_ADC_GET_DATA(p_data) ((p_data)->type1.data) + + +#define ADC_UNIT ADC_UNIT_1 + + +// ADC通道 +//static adc_channel_t channel[2] = {ADC_CHANNEL_6, ADC_CHANNEL_7}; +static adc_channel_t channel[1] = {ADC_CHANNEL_6}; + + +static TaskHandle_t s_task_handle; +static const char *TAG = "ADC_CONTINUOUS"; + +// ADC连续模式的事件回调(一个转换帧完成时) +static bool IRAM_ATTR s_conv_done_cb(adc_continuous_handle_t handle, const adc_continuous_evt_data_t *edata, void *user_data) +{ + BaseType_t mustYield = pdFALSE; + //Notify that ADC continuous driver has done enough number of conversions + //vTaskNotifyGiveFromISR 是 FreeRTOS 提供的一个函数,它允许从中断服务例程(ISR)安全地向任务发送通知 + vTaskNotifyGiveFromISR(s_task_handle, &mustYield); + + return (mustYield == pdTRUE); +} + +// adc初始化 +static void continuous_adc_init(adc_channel_t *channel, uint8_t channel_num, adc_continuous_handle_t *out_handle) +{ + // 创建一个ADC连续模式的句柄 + adc_continuous_handle_t handle = NULL; + + // 配置ADC连续模式的参数 + adc_continuous_handle_cfg_t adc_config = { + .max_store_buf_size = 1024, // 最大存储缓冲区大小 + .conv_frame_size = 256, // 转换帧大小 + }; + ESP_ERROR_CHECK(adc_continuous_new_handle(&adc_config, &handle)); + + // ADC IO + adc_continuous_config_t dig_cfg = { + .sample_freq_hz = 20 * 1000, // 采样频率 + .conv_mode = ADC_CONV_SINGLE_UNIT_1, // 转换模式 + .format = ADC_DIGI_OUTPUT_FORMAT_TYPE1, // 输出格式 + }; + + adc_digi_pattern_config_t adc_pattern[SOC_ADC_PATT_LEN_MAX] = {0}; + dig_cfg.pattern_num = channel_num; // 通道数量 + for (int i = 0; i < channel_num; i++) { + adc_pattern[i].atten = ADC_ATTEN_DB_11; // ADC 衰减 + adc_pattern[i].channel = channel[i] & 0x7; // 通道 + adc_pattern[i].unit = ADC_UNIT; // ADC单元 + adc_pattern[i].bit_width = SOC_ADC_DIGI_MAX_BITWIDTH; // 位宽 + + // 打印配置信息 + // - PRIx8 是一个预处理宏,定义在 C 语言的标准库头文件 中。它用于以可移植的方式格式化输出 uint8_t 类型的数据为十六进制形式。 + ESP_LOGI(TAG, "adc_pattern[%d].atten is :%"PRIx8, i, adc_pattern[i].atten); + ESP_LOGI(TAG, "adc_pattern[%d].channel is :%"PRIx8, i, adc_pattern[i].channel); + ESP_LOGI(TAG, "adc_pattern[%d].unit is :%"PRIx8, i, adc_pattern[i].unit); + } + + // 要使用的 ADC 通道的配置列表 + dig_cfg.adc_pattern = adc_pattern; + ESP_ERROR_CHECK(adc_continuous_config(handle, &dig_cfg)); + + *out_handle = handle; +} + +void app_main(void) +{ + esp_err_t ret; // 返回状态 + uint32_t ret_num = 0; // 转换完成的数据数量 + // 定义接收数组 + uint8_t result[256] = {0}; + // 初始化数组,填充为0xcc + memset(result, 0xcc, 256); + + //获取app_mian任务的句柄。 + s_task_handle = xTaskGetCurrentTaskHandle(); + + // 初始化ADC + adc_continuous_handle_t handle = NULL; + continuous_adc_init(channel, sizeof(channel) / sizeof(adc_channel_t), &handle); + + // 事件回调 + adc_continuous_evt_cbs_t cbs = { + // 当一个转换帧完成时,触发此事件:s_conv_done_cb + .on_conv_done = s_conv_done_cb, + }; + + // 注册事件回调 + ESP_ERROR_CHECK(adc_continuous_register_event_callbacks(handle, &cbs, NULL)); + // 启动ADC连续模式 + ESP_ERROR_CHECK(adc_continuous_start(handle)); + + while (1) { + + /** + * This is to show you the way to use the ADC continuous mode driver event callback. + * This `ulTaskNotifyTake` will block when the data processing in the task is fast. + * However in this example, the data processing (print) is slow, so you barely block here. + * + * Without using this event callback (to notify this task), you can still just call + * `adc_continuous_read()` here in a loop, with/without a certain block timeout. + */ + // ulTaskNotifyTake() 等待通知 + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + + // 生成字符串 + char unit[] = EXAMPLE_ADC_UNIT_STR(ADC_UNIT); + + while (1) { + // 读取ADC数据 + ret = adc_continuous_read(handle, result, 256, &ret_num, 0); + // 读取成功 + if (ret == ESP_OK) { + // 显示读取操作的返回状态和实际读取到的数据字节数 + ESP_LOGI("TASK", "ret is %x, ret_num is %"PRIu32" bytes", ret, ret_num); + // 循环遍历读取到的数据,解析每个ADC数据项,并打印出来 + // - 循环以 SOC_ADC_DIGI_RESULT_BYTES 为步长迭代,这个常量定义了每个ADC数据项的字节大小。 + // - adc_digi_output_data_t 是一个结构体类型,用于解析ADC数据项。 + // - EXAMPLE_ADC_GET_CHANNEL(p) 和 EXAMPLE_ADC_GET_DATA(p) 是宏,用于从 adc_digi_output_data_t 结构体中提取通道号和数据值。 + for (int i = 0; i < ret_num; i += SOC_ADC_DIGI_RESULT_BYTES) { + adc_digi_output_data_t *p = (adc_digi_output_data_t*)&result[i]; + uint32_t chan_num = EXAMPLE_ADC_GET_CHANNEL(p); + uint32_t data = EXAMPLE_ADC_GET_DATA(p); + /*检查通道编号验证,如果通道编号超过最大通道,则数据无效 */ + // - PRIu32 是 C 语言标准库中的宏,它用于以可移植的方式格式化输出 uint32_t 类型的数据。 + if (chan_num < SOC_ADC_CHANNEL_NUM(ADC_UNIT)) { + ESP_LOGI(TAG, "Unit: %s, Channel: %"PRIu32", Value: %"PRIu32, unit, chan_num, data); + } else { + ESP_LOGW(TAG, "Invalid data [%s_%"PRIu32"_%"PRIu32"]", unit, chan_num, data); + } + } + /** + * Because printing is slow, so every time you call `ulTaskNotifyTake`, it will immediately return. + * To avoid a task watchdog timeout, add a delay here. When you replace the way you process the data, + * usually you don't need this delay (as this task will block for a while). + */ + vTaskDelay(1); + } else if (ret == ESP_ERR_TIMEOUT) { + //We try to read `EXAMPLE_READ_LEN` until API returns timeout, which means there's no available data + break; + } + } + } + // 停止ADC连续模式 + ESP_ERROR_CHECK(adc_continuous_stop(handle)); + ESP_ERROR_CHECK(adc_continuous_deinit(handle)); +} diff --git a/code/04.peripheral/basics/adc_oneshot/.gitignore b/code/04.peripheral/basics/adc_oneshot/.gitignore new file mode 100644 index 0000000..8da877b --- /dev/null +++ b/code/04.peripheral/basics/adc_oneshot/.gitignore @@ -0,0 +1,6 @@ +build +*managed_components +dependencies.lock +sdkconfig +sdkconfig.old + diff --git a/code/04.peripheral/basics/adc_oneshot/CMakeLists.txt b/code/04.peripheral/basics/adc_oneshot/CMakeLists.txt new file mode 100644 index 0000000..4d51d49 --- /dev/null +++ b/code/04.peripheral/basics/adc_oneshot/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(adc_oneshot) diff --git a/code/04.peripheral/basics/adc_oneshot/main/CMakeLists.txt b/code/04.peripheral/basics/adc_oneshot/main/CMakeLists.txt new file mode 100644 index 0000000..ac4e3a9 --- /dev/null +++ b/code/04.peripheral/basics/adc_oneshot/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "adc_oneshot.c" + INCLUDE_DIRS ".") diff --git a/code/04.peripheral/basics/adc_oneshot/main/adc_oneshot.c b/code/04.peripheral/basics/adc_oneshot/main/adc_oneshot.c new file mode 100644 index 0000000..037ff1f --- /dev/null +++ b/code/04.peripheral/basics/adc_oneshot/main/adc_oneshot.c @@ -0,0 +1,46 @@ +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_system.h" +#include "esp_log.h" +#include "esp_adc/adc_oneshot.h" + +#define EXAMPLE_ADC1_CHAN0 ADC_CHANNEL_6 // 根据您的硬件配置选择合适的通道 +#define EXAMPLE_ADC1_CHAN1 ADC_CHANNEL_7 // 根据您的硬件配置选择合适的通道 + +static const char* TAG = "ADC_ONESHOT_EXAMPLE"; + +void app_main(void) +{ + adc_oneshot_unit_handle_t adc1_handle; + adc_oneshot_unit_init_cfg_t init_config1 = { + .unit_id = ADC_UNIT_1, + .ulp_mode = ADC_ULP_MODE_DISABLE, + }; + ESP_ERROR_CHECK(adc_oneshot_new_unit(&init_config1, &adc1_handle)); + + adc_oneshot_chan_cfg_t config = { + .bitwidth = ADC_BITWIDTH_DEFAULT, + .atten = ADC_ATTEN_DB_11, // 设置适当的衰减以匹配您的输入电压范围 + }; + + // 配置两个通道 + ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1_handle, EXAMPLE_ADC1_CHAN0, &config)); + ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1_handle, EXAMPLE_ADC1_CHAN1, &config)); + + int adc_raw[2]; + + // 对每个通道进行单次转换并读取结果 + for (int i = 0; i < 10; i++) { + ESP_ERROR_CHECK(adc_oneshot_read(adc1_handle, EXAMPLE_ADC1_CHAN0, &adc_raw[0])); + ESP_LOGI(TAG, "ADC1 Channel[%d] Raw Data: %d", EXAMPLE_ADC1_CHAN0, adc_raw[0]); + + ESP_ERROR_CHECK(adc_oneshot_read(adc1_handle, EXAMPLE_ADC1_CHAN1, &adc_raw[1])); + ESP_LOGI(TAG, "ADC1 Channel[%d] Raw Data: %d", EXAMPLE_ADC1_CHAN1, adc_raw[1]); + + vTaskDelay(pdMS_TO_TICKS(1000)); // 等待1秒再次读取 + } + + // 回收资源 + ESP_ERROR_CHECK(adc_oneshot_del_unit(adc1_handle)); +} diff --git a/code/04.peripheral/basics/dac_cosine/.gitignore b/code/04.peripheral/basics/dac_cosine/.gitignore new file mode 100644 index 0000000..8da877b --- /dev/null +++ b/code/04.peripheral/basics/dac_cosine/.gitignore @@ -0,0 +1,6 @@ +build +*managed_components +dependencies.lock +sdkconfig +sdkconfig.old + diff --git a/code/04.peripheral/basics/dac_cosine/CMakeLists.txt b/code/04.peripheral/basics/dac_cosine/CMakeLists.txt new file mode 100644 index 0000000..b2c0ac7 --- /dev/null +++ b/code/04.peripheral/basics/dac_cosine/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(dac_cosine) diff --git a/code/04.peripheral/basics/dac_cosine/main/CMakeLists.txt b/code/04.peripheral/basics/dac_cosine/main/CMakeLists.txt new file mode 100644 index 0000000..7d58b2c --- /dev/null +++ b/code/04.peripheral/basics/dac_cosine/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "dac_cosine.c" + INCLUDE_DIRS ".") diff --git a/code/04.peripheral/basics/dac_cosine/main/dac_cosine.c b/code/04.peripheral/basics/dac_cosine/main/dac_cosine.c new file mode 100644 index 0000000..7d19237 --- /dev/null +++ b/code/04.peripheral/basics/dac_cosine/main/dac_cosine.c @@ -0,0 +1,36 @@ +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "driver/dac_cosine.h" + + +void app_main(void) +{ + dac_cosine_handle_t chan0_handle; + dac_cosine_handle_t chan1_handle; + /* Normally two channels can only be configured to one frequency + * But we can set force_set_freq bit to force update the frequency + * The example here will produce cosine wave at 8 KHz on both channels */ + dac_cosine_config_t cos0_cfg = { + .chan_id = DAC_CHAN_0, + .freq_hz = 1000, // It will be covered by 8000 in the latter configuration + .clk_src = DAC_COSINE_CLK_SRC_DEFAULT, + .offset = 0, + .phase = DAC_COSINE_PHASE_0, + .atten = DAC_COSINE_ATTEN_DEFAULT, + .flags.force_set_freq = false, + }; + dac_cosine_config_t cos1_cfg = { + .chan_id = DAC_CHAN_1, + .freq_hz = 8000, + .clk_src = DAC_COSINE_CLK_SRC_DEFAULT, + .offset = 0, + .phase = DAC_COSINE_PHASE_180, + .atten = DAC_COSINE_ATTEN_DB_6, + .flags.force_set_freq = true, // set true will allow to overwrite the frequency that set before + }; + ESP_ERROR_CHECK(dac_cosine_new_channel(&cos0_cfg, &chan0_handle)); + ESP_ERROR_CHECK(dac_cosine_new_channel(&cos1_cfg, &chan1_handle)); + ESP_ERROR_CHECK(dac_cosine_start(chan0_handle)); + ESP_ERROR_CHECK(dac_cosine_start(chan1_handle)); + +} diff --git a/code/04.peripheral/basics/dac_oneshot/.gitignore b/code/04.peripheral/basics/dac_oneshot/.gitignore new file mode 100644 index 0000000..8da877b --- /dev/null +++ b/code/04.peripheral/basics/dac_oneshot/.gitignore @@ -0,0 +1,6 @@ +build +*managed_components +dependencies.lock +sdkconfig +sdkconfig.old + diff --git a/code/04.peripheral/basics/dac_oneshot/CMakeLists.txt b/code/04.peripheral/basics/dac_oneshot/CMakeLists.txt new file mode 100644 index 0000000..ef439e5 --- /dev/null +++ b/code/04.peripheral/basics/dac_oneshot/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(dac_oneshot) diff --git a/code/04.peripheral/basics/dac_oneshot/main/CMakeLists.txt b/code/04.peripheral/basics/dac_oneshot/main/CMakeLists.txt new file mode 100644 index 0000000..19bee95 --- /dev/null +++ b/code/04.peripheral/basics/dac_oneshot/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "dac_oneshot.c" + INCLUDE_DIRS ".") diff --git a/code/04.peripheral/basics/dac_oneshot/main/dac_oneshot.c b/code/04.peripheral/basics/dac_oneshot/main/dac_oneshot.c new file mode 100644 index 0000000..2cde727 --- /dev/null +++ b/code/04.peripheral/basics/dac_oneshot/main/dac_oneshot.c @@ -0,0 +1,39 @@ +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "driver/dac_oneshot.h" +//#include "esp_check.h" + +static void dac_output_task(void *args) +{ + dac_oneshot_handle_t handle = (dac_oneshot_handle_t)args; + uint32_t val = 0; + while (1) { + /* Set the voltage every 100 ms */ + ESP_ERROR_CHECK(dac_oneshot_output_voltage(handle, val)); + val += 10; + val %= 250; + vTaskDelay(pdMS_TO_TICKS(500)); + } +} + +void app_main(void) +{ + /* DAC oneshot init */ + dac_oneshot_handle_t chan0_handle; + dac_oneshot_config_t chan0_cfg = { + .chan_id = DAC_CHAN_0, + }; + ESP_ERROR_CHECK(dac_oneshot_new_channel(&chan0_cfg, &chan0_handle)); + + dac_oneshot_handle_t chan1_handle; + dac_oneshot_config_t chan1_cfg = { + .chan_id = DAC_CHAN_1, + }; + ESP_ERROR_CHECK(dac_oneshot_new_channel(&chan1_cfg, &chan1_handle)); + + /* DAC oneshot outputting threads */ + xTaskCreate(dac_output_task, "dac_chan0_output_task", 4096, chan0_handle, 5, NULL); + vTaskDelay(pdMS_TO_TICKS(500)); // To differential the output of two channels + xTaskCreate(dac_output_task, "dac_chan1_output_task", 4096, chan1_handle, 5, NULL); + +} diff --git a/code/04.peripheral/basics/gpio/.gitignore b/code/04.peripheral/basics/gpio/.gitignore new file mode 100644 index 0000000..8da877b --- /dev/null +++ b/code/04.peripheral/basics/gpio/.gitignore @@ -0,0 +1,6 @@ +build +*managed_components +dependencies.lock +sdkconfig +sdkconfig.old + diff --git a/code/04.peripheral/basics/gpio/CMakeLists.txt b/code/04.peripheral/basics/gpio/CMakeLists.txt new file mode 100644 index 0000000..b89bdad --- /dev/null +++ b/code/04.peripheral/basics/gpio/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(gpio) diff --git a/code/04.peripheral/basics/gpio/main/CMakeLists.txt b/code/04.peripheral/basics/gpio/main/CMakeLists.txt new file mode 100644 index 0000000..19bb736 --- /dev/null +++ b/code/04.peripheral/basics/gpio/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "gpio.c" + INCLUDE_DIRS ".") diff --git a/code/04.peripheral/basics/gpio/main/gpio.c b/code/04.peripheral/basics/gpio/main/gpio.c new file mode 100644 index 0000000..93e124f --- /dev/null +++ b/code/04.peripheral/basics/gpio/main/gpio.c @@ -0,0 +1,31 @@ +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "driver/gpio.h" + +#define LED_GPIO GPIO_NUM_2 +#define BUTTON_GPIO GPIO_NUM_0 + +void app_main(void) +{ + // 初始化LED GPIO为输出模式 + gpio_set_direction(LED_GPIO, GPIO_MODE_OUTPUT); + + // 初始化按钮GPIO为输入模式 + gpio_set_direction(BUTTON_GPIO, GPIO_MODE_INPUT); + gpio_set_pull_mode(BUTTON_GPIO, GPIO_PULLUP_ONLY); + + while (1) { + // 读取按钮状态 + int button_state = gpio_get_level(BUTTON_GPIO); + + // 如果按钮被按下(逻辑低电平),点亮LED + if(button_state == 0) { + gpio_set_level(LED_GPIO, 1); + } else { + gpio_set_level(LED_GPIO, 0); + } + + vTaskDelay(10 / portTICK_PERIOD_MS); + } +} diff --git a/code/04.peripheral/basics/gpio_exit/.gitignore b/code/04.peripheral/basics/gpio_exit/.gitignore new file mode 100644 index 0000000..8da877b --- /dev/null +++ b/code/04.peripheral/basics/gpio_exit/.gitignore @@ -0,0 +1,6 @@ +build +*managed_components +dependencies.lock +sdkconfig +sdkconfig.old + diff --git a/code/04.peripheral/basics/gpio_exit/CMakeLists.txt b/code/04.peripheral/basics/gpio_exit/CMakeLists.txt new file mode 100644 index 0000000..308bddc --- /dev/null +++ b/code/04.peripheral/basics/gpio_exit/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(gpio_exit) diff --git a/code/04.peripheral/basics/gpio_exit/main/CMakeLists.txt b/code/04.peripheral/basics/gpio_exit/main/CMakeLists.txt new file mode 100644 index 0000000..e5e4443 --- /dev/null +++ b/code/04.peripheral/basics/gpio_exit/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "gpio_exit.c" + INCLUDE_DIRS ".") diff --git a/code/04.peripheral/basics/gpio_exit/main/gpio_exit.c b/code/04.peripheral/basics/gpio_exit/main/gpio_exit.c new file mode 100644 index 0000000..160f19c --- /dev/null +++ b/code/04.peripheral/basics/gpio_exit/main/gpio_exit.c @@ -0,0 +1,34 @@ +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "driver/gpio.h" + +#define LED_GPIO GPIO_NUM_2 +#define BUTTON_GPIO GPIO_NUM_0 + +// 声明一个用于处理GPIO中断的函数 +static void IRAM_ATTR gpio_isr_handler(void* arg) { + // 读取按钮状态并设置LED + int button_state = gpio_get_level(BUTTON_GPIO); + gpio_set_level(LED_GPIO, button_state == 0 ? 1 : 0); +} + +void app_main(void) { + // 初始化LED GPIO为输出模式 + gpio_set_direction(LED_GPIO, GPIO_MODE_OUTPUT); + + // 初始化按钮GPIO为输入模式,并设置为上拉 + gpio_set_direction(BUTTON_GPIO, GPIO_MODE_INPUT); + gpio_set_pull_mode(BUTTON_GPIO, GPIO_PULLUP_ONLY); + + // 安装GPIO服务 + gpio_install_isr_service(0); + // 配置GPIO中断类型,并注册中断服务函数 + gpio_set_intr_type(BUTTON_GPIO, GPIO_INTR_ANYEDGE); + gpio_isr_handler_add(BUTTON_GPIO, gpio_isr_handler, NULL); + + while (1) { + // 在中断模式下,主循环可以执行其他任务或进入睡眠状态 + vTaskDelay(portMAX_DELAY); // 使用portMAX_DELAY使任务永久挂起,直到中断唤醒 + } +} diff --git a/code/04.peripheral/basics/gptimer/.gitignore b/code/04.peripheral/basics/gptimer/.gitignore new file mode 100644 index 0000000..8da877b --- /dev/null +++ b/code/04.peripheral/basics/gptimer/.gitignore @@ -0,0 +1,6 @@ +build +*managed_components +dependencies.lock +sdkconfig +sdkconfig.old + diff --git a/code/04.peripheral/basics/gptimer/CMakeLists.txt b/code/04.peripheral/basics/gptimer/CMakeLists.txt new file mode 100644 index 0000000..a54b7b7 --- /dev/null +++ b/code/04.peripheral/basics/gptimer/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(gptimer) diff --git a/code/04.peripheral/basics/gptimer/main/CMakeLists.txt b/code/04.peripheral/basics/gptimer/main/CMakeLists.txt new file mode 100644 index 0000000..063c585 --- /dev/null +++ b/code/04.peripheral/basics/gptimer/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "gptimer.c" + INCLUDE_DIRS ".") diff --git a/code/04.peripheral/basics/gptimer/main/gptimer.c b/code/04.peripheral/basics/gptimer/main/gptimer.c new file mode 100644 index 0000000..020ae7a --- /dev/null +++ b/code/04.peripheral/basics/gptimer/main/gptimer.c @@ -0,0 +1,196 @@ +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" +#include "driver/gptimer.h" +#include "esp_log.h" + +static const char *TAG = "gptimer"; + +typedef struct { + uint64_t event_count; +} example_queue_element_t; + +// 定时器警报事件的回调函数(案例1) +// 三个参数:定时器句柄 timer、事件数据指针 edata 和用户数据指针 user_data。 +static bool IRAM_ATTR example_timer_on_alarm_cb_v1(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_data) +{ + BaseType_t high_task_awoken = pdFALSE; + QueueHandle_t queue = (QueueHandle_t)user_data; + // 立即停止计时器 + gptimer_stop(timer); + // 从事件数据中获取计数值,并将其存储在 example_queue_element_t 结构体变量 ele 的 event_count 字段中。 + example_queue_element_t ele = { + .event_count = edata->count_value + }; + //使用 xQueueSendFromISR() 函数将 ele 变量发送到队列中 + xQueueSendFromISR(queue, &ele, &high_task_awoken); + // return whether we need to yield at the end of ISR + return (high_task_awoken == pdTRUE); +} + +// 定时器警报事件的回调函数(案例2) +static bool IRAM_ATTR example_timer_on_alarm_cb_v2(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_data) +{ + BaseType_t high_task_awoken = pdFALSE; + QueueHandle_t queue = (QueueHandle_t)user_data; + // Retrieve count value and send to queue + example_queue_element_t ele = { + .event_count = edata->count_value + }; + xQueueSendFromISR(queue, &ele, &high_task_awoken); + // return whether we need to yield at the end of ISR + return (high_task_awoken == pdTRUE); +} + +// 定时器警报事件的回调函数(案例3:动态更新报警值) +static bool IRAM_ATTR example_timer_on_alarm_cb_v3(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_data) +{ + BaseType_t high_task_awoken = pdFALSE; + QueueHandle_t queue = (QueueHandle_t)user_data; + // Retrieve count value and send to queue + example_queue_element_t ele = { + .event_count = edata->count_value + }; + xQueueSendFromISR(queue, &ele, &high_task_awoken); + // reconfigure alarm value + gptimer_alarm_config_t alarm_config = { + .alarm_count = edata->alarm_value + 1000000, // alarm in next 1s + }; + gptimer_set_alarm_action(timer, &alarm_config); + // return whether we need to yield at the end of ISR + return (high_task_awoken == pdTRUE); +} + +void app_main(void) +{ + // 定义一个 example_queue_element_t 类型的变量 ele + example_queue_element_t ele; + //创建了一个长度为 10,每个元素大小为 example_queue_element_t 类型的队列,并将其赋值给 queue 变量。 + QueueHandle_t queue = xQueueCreate(10, sizeof(example_queue_element_t)); + if (!queue) { + ESP_LOGE(TAG, "创建队列失败"); + return; + } + + // 初始化定时器 + ESP_LOGW(TAG, "创建分辨率为 1 MHz 的通用定时器句柄"); + gptimer_handle_t gptimer = NULL; + gptimer_config_t timer_config = { + .clk_src = GPTIMER_CLK_SRC_DEFAULT, + .direction = GPTIMER_COUNT_UP, + .resolution_hz = 1000000, // 1MHz, 1 tick=1us + }; + ESP_ERROR_CHECK(gptimer_new_timer(&timer_config, &gptimer)); + + // 注册定时器事件回调函数(警报事件的回调函数) + gptimer_event_callbacks_t cbs = { + .on_alarm = example_timer_on_alarm_cb_v1, + }; + ESP_ERROR_CHECK(gptimer_register_event_callbacks(gptimer, &cbs, queue)); + + // 使能定时器 + ESP_LOGI(TAG, "Enable timer"); + ESP_ERROR_CHECK(gptimer_enable(gptimer)); + + // 设置定时器的周期为 1s(触发警报事件的目标计数值) + ESP_LOGI(TAG, "Start timer, stop it at alarm event"); + gptimer_alarm_config_t alarm_config1 = { + .alarm_count = 1000000, // period = 1s + }; + // 设置定时器的报警事件 + ESP_ERROR_CHECK(gptimer_set_alarm_action(gptimer, &alarm_config1)); + // 启动定时器 + ESP_ERROR_CHECK(gptimer_start(gptimer)); + + // 等待定时器报警事件(从队列中接收数据,接收到的数据将会存储在 &ele 中) + if (xQueueReceive(queue, &ele, pdMS_TO_TICKS(2000))) { + ESP_LOGI(TAG, "Timer stopped, count=%llu", ele.event_count); + } else { + ESP_LOGW(TAG, "Missed one count event"); + } + + // 设置定时器的计数值(异步更新) + ESP_LOGI(TAG, "Set count value"); + ESP_ERROR_CHECK(gptimer_set_raw_count(gptimer, 100)); + ESP_LOGI(TAG, "Get count value"); + + // 获取定时器的计数值 + uint64_t count; + ESP_ERROR_CHECK(gptimer_get_raw_count(gptimer, &count)); + ESP_LOGI(TAG, "Timer count value=%llu", count); + + //--------------------------------------------------------------------// + ESP_LOGW(TAG, "案例1结束,案例2开始"); + //--------------------------------------------------------------------// + + // 在更新报警回调之前,我们应该确保计时器没有处于启用状态 + ESP_LOGI(TAG, "Disable timer"); + ESP_ERROR_CHECK(gptimer_disable(gptimer)); + // 设置一个新的回调函数 + cbs.on_alarm = example_timer_on_alarm_cb_v2; + ESP_ERROR_CHECK(gptimer_register_event_callbacks(gptimer, &cbs, queue)); + ESP_LOGI(TAG, "Enable timer"); + ESP_ERROR_CHECK(gptimer_enable(gptimer)); + + // 重新设置报警条件 + ESP_LOGI(TAG, "Start timer, auto-reload at alarm event"); + gptimer_alarm_config_t alarm_config2 = { + .reload_count = 0, + .alarm_count = 1000000, // period = 1s + .flags.auto_reload_on_alarm = true, //报警事件发生后立即通过硬件重新加载计数值 + }; + // 设置定时器的报警事件 + ESP_ERROR_CHECK(gptimer_set_alarm_action(gptimer, &alarm_config2)); + ESP_ERROR_CHECK(gptimer_start(gptimer)); + + // 循环次数为4次。在每次循环中,通过 xQueueReceive() 函数从队列中接收数据,并等待最多2秒。如果成功接收到数据,则打印定时器重新加载的消息 + int record = 4; + while (record) { + if (xQueueReceive(queue, &ele, pdMS_TO_TICKS(2000))) { + ESP_LOGI(TAG, "Timer reloaded, count=%llu", ele.event_count); + record--; + } else { + ESP_LOGW(TAG, "Missed one count event"); + } + } + ESP_LOGI(TAG, "Stop timer"); + ESP_ERROR_CHECK(gptimer_stop(gptimer)); + + ESP_LOGI(TAG, "Disable timer"); + ESP_ERROR_CHECK(gptimer_disable(gptimer)); + + //--------------------------------------------------------------------// + ESP_LOGW(TAG, "案例2结束,案例3开始"); + //--------------------------------------------------------------------// + // 案例3动态更新报警值 + cbs.on_alarm = example_timer_on_alarm_cb_v3; + ESP_ERROR_CHECK(gptimer_register_event_callbacks(gptimer, &cbs, queue)); + ESP_LOGI(TAG, "Enable timer"); + ESP_ERROR_CHECK(gptimer_enable(gptimer)); + + ESP_LOGI(TAG, "Start timer, update alarm value dynamically"); + gptimer_alarm_config_t alarm_config3 = { + .alarm_count = 1000000, // period = 1s + }; + ESP_ERROR_CHECK(gptimer_set_alarm_action(gptimer, &alarm_config3)); + ESP_ERROR_CHECK(gptimer_start(gptimer)); + record = 4; + while (record) { + if (xQueueReceive(queue, &ele, pdMS_TO_TICKS(2000))) { + ESP_LOGI(TAG, "Timer alarmed, count=%llu", ele.event_count); + record--; + } else { + ESP_LOGW(TAG, "Missed one count event"); + } + } + + ESP_LOGI(TAG, "Stop timer"); + ESP_ERROR_CHECK(gptimer_stop(gptimer)); + ESP_LOGI(TAG, "Disable timer"); + ESP_ERROR_CHECK(gptimer_disable(gptimer)); + ESP_LOGI(TAG, "Delete timer"); + ESP_ERROR_CHECK(gptimer_del_timer(gptimer)); + + vQueueDelete(queue); +} diff --git a/code/04.peripheral/basics/i2c_bh1750/.gitignore b/code/04.peripheral/basics/i2c_bh1750/.gitignore new file mode 100644 index 0000000..8da877b --- /dev/null +++ b/code/04.peripheral/basics/i2c_bh1750/.gitignore @@ -0,0 +1,6 @@ +build +*managed_components +dependencies.lock +sdkconfig +sdkconfig.old + diff --git a/code/04.peripheral/basics/i2c_bh1750/CMakeLists.txt b/code/04.peripheral/basics/i2c_bh1750/CMakeLists.txt new file mode 100644 index 0000000..4a255a2 --- /dev/null +++ b/code/04.peripheral/basics/i2c_bh1750/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(i2c_bh1750) diff --git a/code/04.peripheral/basics/i2c_bh1750/main/CMakeLists.txt b/code/04.peripheral/basics/i2c_bh1750/main/CMakeLists.txt new file mode 100644 index 0000000..cf2c455 --- /dev/null +++ b/code/04.peripheral/basics/i2c_bh1750/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") diff --git a/code/04.peripheral/basics/i2c_bh1750/main/main.c b/code/04.peripheral/basics/i2c_bh1750/main/main.c new file mode 100644 index 0000000..26bf460 --- /dev/null +++ b/code/04.peripheral/basics/i2c_bh1750/main/main.c @@ -0,0 +1,127 @@ + +#include +#include "esp_log.h" +#include "driver/i2c.h" +#include "sdkconfig.h" + +static const char *TAG = "main"; + + +// I2C Master 配置 +#define I2C_MASTER_SCL_IO 19 /*!< gpio number for I2C master clock */ +#define I2C_MASTER_SDA_IO 18 /*!< gpio number for I2C master data */ +#define I2C_MASTER_NUM I2C_NUM_0 /*!< I2C port number for master dev */ +#define I2C_MASTER_FREQ_HZ 100000 /*!< I2C master clock frequency */ +#define I2C_MASTER_TX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */ +#define I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */ + +// BH1750 Sensor 配置 +#define BH1750_SENSOR_ADDR 0x23 //0010_0011 // 传感器地址 +#define BH1750_CMD_START 0x23 //0010_0011 // 传感器模式:单次采集模式 +#define WRITE_BIT I2C_MASTER_WRITE // I2C 读取位 :1 +#define READ_BIT I2C_MASTER_READ // I2C 写入位 :0 +#define ACK_CHECK_EN 0x1 // 检测从机应答 +#define ACK_CHECK_DIS 0x0 // 不检测从机应答 +#define ACK_VAL 0x0 // 响应值 +#define NACK_VAL 0x1 // 无响应值 + + + +/** + * @brief test code to operate on BH1750 sensor + * + * 1. set operation mode(e.g One time L-resolution mode) + * _________________________________________________________________ + * | start | slave_addr + wr_bit + ack | write 1 byte + ack | stop | + * --------|---------------------------|---------------------|------| + * 2. wait more than 24 ms + * 3. read data + * ______________________________________________________________________________________ + * | start | slave_addr + rd_bit + ack | read 1 byte + ack | read 1 byte + nack | stop | + * --------|---------------------------|--------------------|--------------------|------| + */ +static esp_err_t i2c_master_sensor_test(i2c_port_t i2c_num, uint8_t *data_h, uint8_t *data_l) +{ + int ret; + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); // 创建I2C命令 + i2c_master_start(cmd); // 起始信号 + i2c_master_write_byte(cmd, BH1750_SENSOR_ADDR << 1 | WRITE_BIT, ACK_CHECK_EN); //从机地址及读写位 + i2c_master_write_byte(cmd, BH1750_CMD_START, ACK_CHECK_EN); //数据位(数组) + i2c_master_stop(cmd); //终止信号 + ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_PERIOD_MS); //i2c_num 发送这个数据帧,timeout设置为1000毫秒 + i2c_cmd_link_delete(cmd); //删除i2c_cmd_handle_t对象,释放资源 + if (ret != ESP_OK) { + return ret; + } + vTaskDelay(30 / portTICK_PERIOD_MS); + cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, BH1750_SENSOR_ADDR << 1 | READ_BIT, ACK_CHECK_EN); //从机地址及读写位 + i2c_master_read_byte(cmd, data_h, ACK_VAL); //读取数据(高位) + i2c_master_read_byte(cmd, data_l, NACK_VAL); //读取数据(低位) + i2c_master_stop(cmd); + ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_PERIOD_MS); + i2c_cmd_link_delete(cmd); + return ret; +} + +/** + * @brief I2C master initialization + */ +static esp_err_t i2c_master_init(void) +{ + // 配置I2C + int i2c_master_port = I2C_MASTER_NUM; + i2c_config_t conf = { + .mode = I2C_MODE_MASTER, + .sda_io_num = I2C_MASTER_SDA_IO, + .sda_pullup_en = GPIO_PULLUP_ENABLE, + .scl_io_num = I2C_MASTER_SCL_IO, + .scl_pullup_en = GPIO_PULLUP_ENABLE, + .master.clk_speed = I2C_MASTER_FREQ_HZ, + // .clk_flags = 0, /*!< Optional, you can use I2C_SCLK_SRC_FLAG_* flags to choose i2c source clock here. */ + }; + esp_err_t err = i2c_param_config(i2c_master_port, &conf); + if (err != ESP_OK) { + return err; + } + // 安装I2C驱动 + return i2c_driver_install(i2c_master_port, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0); +} + + +static void i2c_task(void *arg) +{ + int ret; // Return value + int task_idx = (int)arg; + uint8_t sensor_data_h, sensor_data_l; + int cnt = 0; + + while (1) { + // 读取数据 + ESP_LOGI(TAG, "TASK[%d] test cnt: %d", task_idx, cnt++); + ret = i2c_master_sensor_test(I2C_MASTER_NUM, &sensor_data_h, &sensor_data_l); + if (ret == ESP_ERR_TIMEOUT) { + ESP_LOGE(TAG, "I2C Timeout"); + } else if (ret == ESP_OK) { + printf("*******************\n"); + printf("TASK[%d] MASTER READ SENSOR( BH1750 )\n", task_idx); + printf("*******************\n"); + printf("data_h: %02x\n", sensor_data_h); + printf("data_l: %02x\n", sensor_data_l); + printf("sensor val: %.02f [Lux]\n", (sensor_data_h << 8 | sensor_data_l) / 1.2); + } else { + ESP_LOGW(TAG, "%s: No ack, sensor not connected...skip...", esp_err_to_name(ret)); + } + vTaskDelay(1000 / portTICK_PERIOD_MS); + } + +} + +void app_main(void) +{ + // 初始化I2C + ESP_ERROR_CHECK(i2c_master_init()); + // 创建I2C采集任务 + xTaskCreate(i2c_task, "i2c_task", 1024 * 2, (void *)0, 10, NULL); +} diff --git a/code/04.peripheral/basics/i2c_tools/.gitignore b/code/04.peripheral/basics/i2c_tools/.gitignore new file mode 100644 index 0000000..8da877b --- /dev/null +++ b/code/04.peripheral/basics/i2c_tools/.gitignore @@ -0,0 +1,6 @@ +build +*managed_components +dependencies.lock +sdkconfig +sdkconfig.old + diff --git a/code/04.peripheral/basics/i2c_tools/CMakeLists.txt b/code/04.peripheral/basics/i2c_tools/CMakeLists.txt new file mode 100644 index 0000000..e482e2a --- /dev/null +++ b/code/04.peripheral/basics/i2c_tools/CMakeLists.txt @@ -0,0 +1,8 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/system/console/advanced/components) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(i2c_tools) diff --git a/code/04.peripheral/basics/i2c_tools/README.md b/code/04.peripheral/basics/i2c_tools/README.md new file mode 100644 index 0000000..e40d4b0 --- /dev/null +++ b/code/04.peripheral/basics/i2c_tools/README.md @@ -0,0 +1,209 @@ +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | + +# I2C Tools Example + +(See the README.md file in the upper level 'examples' directory for more information about examples.) + +## Overview + +[I2C Tools](https://i2c.wiki.kernel.org/index.php/I2C_Tools) is a simple but very useful tool for developing I2C related applications, which is also famous in Linux platform. This example just implements some of basic features of [I2C Tools](https://i2c.wiki.kernel.org/index.php/I2C_Tools) based on [esp32 console component](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/console.html). As follows, this example supports five command-line tools: + +1. `i2cconfig`: It will configure the I2C bus with specific GPIO number, port number and frequency. +2. `i2cdetect`: It will scan an I2C bus for devices and output a table with the list of detected devices on the bus. +3. `i2cget`: It will read registers visible through the I2C bus. +4. `i2cset`: It will set registers visible through the I2C bus. +5. `i2cdump`: It will examine registers visible through the I2C bus. + +If you have some trouble in developing I2C related applications, or just want to test some functions of one I2C device, you can play with this example first. + +## How to use example + +### Hardware Required + +To run this example, you should have any ESP32, ESP32-S and ESP32-C based development board. For test purpose, you should have a kind of device with I2C interface as well. Here we will take the CCS811 sensor as an example to show how to test the function of this sensor without writing any code (just use the command-line tools supported by this example). For more information about CCS811, you can consult the [online datasheet](http://ams.com/ccs811). + +#### Pin Assignment: + +**Note:** The following pin assignments are used by default, you can change them with `i2cconfig` command at any time. + +| | SDA | SCL | GND | Other | VCC | +| ------------------- | ------ | ------ | ---- | ----- | ---- | +| ESP32 I2C Master | GPIO18 | GPIO19 | GND | GND | 3.3V | +| ESP32-S2 I2C Master | GPIO18 | GPIO19 | GND | GND | 3.3V | +| ESP32-S3 I2C Master | GPIO1 | GPIO2 | GND | GND | 3.3V | +| ESP32-C3 I2C Master | GPIO5 | GPIO6 | GND | GND | 3.3V | +| ESP32-C2 I2C Master | GPIO5 | GPIO6 | GND | GND | 3.3V | +| ESP32-H2 I2C Master | GPIO1 | GPIO2 | GND | GND | 3.3V | +| Sensor | SDA | SCL | GND | WAK | VCC | + +**Note:** It is recommended to add external pull-up resistors for SDA/SCL pins to make the communication more stable, though the driver will enable internal pull-up resistors. + +### Configure the project + +Open the project configuration menu (`idf.py menuconfig`). Then go into `Example Configuration` menu. + +- You can choose whether or not to save command history into flash in `Store command history in flash` option. + +### Build and Flash + +Run `idf.py -p PORT flash monitor` to build and flash the project.. + +(To exit the serial monitor, type ``Ctrl-]``.) + +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. + +## Example Output + +### Check all supported commands and their usages + +```bash + ============================================================== + | Steps to Use i2c-tools on ESP32 | + | | + | 1. Try 'help', check all supported commands | + | 2. Try 'i2cconfig' to configure your I2C bus | + | 3. Try 'i2cdetect' to scan devices on the bus | + | 4. Try 'i2cget' to get the content of specific register | + | 5. Try 'i2cset' to set the value of specific register | + | 6. Try 'i2cdump' to dump all the register (Experiment) | + | | + ============================================================== + +i2c-tools> help +help + Print the list of registered commands + +i2cconfig [--port=<0|1>] [--freq=] --sda= --scl= + Config I2C bus + --port=<0|1> Set the I2C bus port number + --freq= Set the frequency(Hz) of I2C bus + --sda= Set the gpio for I2C SDA + --scl= Set the gpio for I2C SCL + +i2cdetect + Scan I2C bus for devices + +i2cget -c [-r ] [-l ] + Read registers visible through the I2C bus + -c, --chip= Specify the address of the chip on that bus + -r, --register= Specify the address on that chip to read from + -l, --length= Specify the length to read from that data address + +i2cset -c [-r ] []... + Set registers visible through the I2C bus + -c, --chip= Specify the address of the chip on that bus + -r, --register= Specify the address on that chip to read from + Specify the data to write to that data address + +i2cdump -c [-s ] + Examine registers visible through the I2C bus + -c, --chip= Specify the address of the chip on that bus + -s, --size= Specify the size of each read + +free + Get the current size of free heap memory + +heap + Get minimum size of free heap memory that was available during program execu + tion + +version + Get version of chip and SDK + +restart + Software reset of the chip + +deep_sleep [-t ] [--io=] [--io_level=<0|1>] + Enter deep sleep mode. Two wakeup modes are supported: timer and GPIO. If no + wakeup option is specified, will sleep indefinitely. + -t, --time= Wake up time, ms + --io= If specified, wakeup using GPIO with given number + --io_level=<0|1> GPIO level to trigger wakeup + +light_sleep [-t ] [--io=]... [--io_level=<0|1>]... + Enter light sleep mode. Two wakeup modes are supported: timer and GPIO. Mult + iple GPIO pins can be specified using pairs of 'io' and 'io_level' arguments + . Will also wake up on UART input. + -t, --time= Wake up time, ms + --io= If specified, wakeup using GPIO with given number + --io_level=<0|1> GPIO level to trigger wakeup + +tasks + Get information about running tasks +``` + +### Configure the I2C bus + +```bash +esp32> i2cconfig --port=0 --sda=18 --scl=19 --freq=100000 +``` + +* `--port` option to specify the port of I2C, here we choose port 0 for test. +* `--sda` and `--scl` options to specify the gpio number used by I2C bus, here we choose GPIO18 as the SDA and GPIO19 as the SCL. +* `--freq` option to specify the frequency of I2C bus, here we set to 100KHz. + +### Check the I2C address (7 bits) on the I2C bus + +```bash +esp32> i2cdetect + 0 1 2 3 4 5 6 7 8 9 a b c d e f +00: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- +10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- +20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- +30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- +40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- +50: -- -- -- -- -- -- -- -- -- -- -- 5b -- -- -- -- +60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- +70: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- +``` + +* Here we found the address of CCS811 is 0x5b. + +### Get the value of status register + +```bash +esp32> i2cget -c 0x5b -r 0x00 -l 1 +0x10 +``` + +* `-c` option to specify the address of I2C device (acquired from `i2cdetect` command). +* `-r` option to specify the register address you want to inspect. +* `-l` option to specify the length of the content. +* Here the returned value 0x10 means that the sensor is just in the boot mode and is ready to go into application mode. For more information about CCS811 you should consult the [official website](http://ams.com/ccs811). + +### Change the working mode + +```bash +esp32> i2cset -c 0x5b -r 0xF4 +I (734717) cmd_i2ctools: Write OK +esp32> i2cset -c 0x5b -r 0x01 0x10 +I (1072047) cmd_i2ctools: Write OK +esp32> i2cget -c 0x5b -r 0x00 -l 1 +0x98 +``` + +* Here we change the mode from boot to application and set a proper measure mode (by writing 0x10 to register 0x01) +* Now the status value of the sensor is 0x98, which means a valid data is ready to read + +### Read the sensor data + +```bash +esp32> i2cget -c 0x5b -r 0x02 -l 8 +0x01 0xb0 0x00 0x04 0x98 0x00 0x19 0x8f +``` + +* The register 0x02 will output 8 bytes result, mainly including value of eCO~2~、TVOC and there raw value. So the value of eCO~2~ is 0x01b0 ppm and value of TVOC is 0x04 ppb. + +## Troubleshooting + +* I don’t find any available address when running `i2cdetect` command. + * Make sure your wiring connection is right. + * Some sensor will have a “wake up” pin, via which user can put the sensor into a sleep mode. So make sure your sensor in **not** in the sleep state. + * Reset you I2C device, and then run `i2cdetect` again. +* I can’t get the right content when running `i2cdump` command. + * Currently the `i2cdump` only support those who have the same content length of registers inside the I2C device. For example, if a device have three register addresses, and the content length at these address are 1 byte, 2 bytes and 4 bytes. In this case you should not expect this command to dump the register correctly. + + +(For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you as soon as possible.) + diff --git a/code/04.peripheral/basics/i2c_tools/main/CMakeLists.txt b/code/04.peripheral/basics/i2c_tools/main/CMakeLists.txt new file mode 100644 index 0000000..60f0989 --- /dev/null +++ b/code/04.peripheral/basics/i2c_tools/main/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS "i2ctools_example_main.c" + "cmd_i2ctools.c" + INCLUDE_DIRS ".") diff --git a/code/04.peripheral/basics/i2c_tools/main/Kconfig.projbuild b/code/04.peripheral/basics/i2c_tools/main/Kconfig.projbuild new file mode 100644 index 0000000..83d85ce --- /dev/null +++ b/code/04.peripheral/basics/i2c_tools/main/Kconfig.projbuild @@ -0,0 +1,10 @@ +menu "Example Configuration" + + config EXAMPLE_STORE_HISTORY + bool "Store command history in flash" + default y + help + Linenoise line editing library provides functions to save and load + command history. If this option is enabled, initalizes a FAT filesystem + and uses it to store command history. +endmenu diff --git a/code/04.peripheral/basics/i2c_tools/main/cmd_i2ctools.c b/code/04.peripheral/basics/i2c_tools/main/cmd_i2ctools.c new file mode 100644 index 0000000..844be5e --- /dev/null +++ b/code/04.peripheral/basics/i2c_tools/main/cmd_i2ctools.c @@ -0,0 +1,414 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +/* cmd_i2ctools.c + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ +#include +#include "argtable3/argtable3.h" +#include "driver/i2c.h" +#include "esp_console.h" +#include "esp_log.h" + +#define I2C_MASTER_TX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */ +#define I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */ +#define WRITE_BIT I2C_MASTER_WRITE /*!< I2C master write */ +#define READ_BIT I2C_MASTER_READ /*!< I2C master read */ +#define ACK_CHECK_EN 0x1 /*!< I2C master will check ack from slave*/ +#define ACK_CHECK_DIS 0x0 /*!< I2C master will not check ack from slave */ +#define ACK_VAL 0x0 /*!< I2C ack value */ +#define NACK_VAL 0x1 /*!< I2C nack value */ + +static const char *TAG = "cmd_i2ctools"; + +#if CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32H2 +static gpio_num_t i2c_gpio_sda = 1; +static gpio_num_t i2c_gpio_scl = 2; +#elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2 +static gpio_num_t i2c_gpio_sda = 5; +static gpio_num_t i2c_gpio_scl = 6; +#else +static gpio_num_t i2c_gpio_sda = 8; + static gpio_num_t i2c_gpio_scl = 18; +#endif + +static uint32_t i2c_frequency = 100000; +static i2c_port_t i2c_port = I2C_NUM_0; + +static esp_err_t i2c_get_port(int port, i2c_port_t *i2c_port) +{ + if (port >= I2C_NUM_MAX) { + ESP_LOGE(TAG, "Wrong port number: %d", port); + return ESP_FAIL; + } + *i2c_port = port; + return ESP_OK; +} + +static esp_err_t i2c_master_driver_initialize(void) +{ + i2c_config_t conf = { + .mode = I2C_MODE_MASTER, + .sda_io_num = i2c_gpio_sda, + .sda_pullup_en = GPIO_PULLUP_ENABLE, + .scl_io_num = i2c_gpio_scl, + .scl_pullup_en = GPIO_PULLUP_ENABLE, + .master.clk_speed = i2c_frequency, + // .clk_flags = 0, /*!< Optional, you can use I2C_SCLK_SRC_FLAG_* flags to choose i2c source clock here. */ + }; + return i2c_param_config(i2c_port, &conf); +} + +static struct { + struct arg_int *port; + struct arg_int *freq; + struct arg_int *sda; + struct arg_int *scl; + struct arg_end *end; +} i2cconfig_args; + +static int do_i2cconfig_cmd(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **)&i2cconfig_args); + if (nerrors != 0) { + arg_print_errors(stderr, i2cconfig_args.end, argv[0]); + return 0; + } + + /* Check "--port" option */ + if (i2cconfig_args.port->count) { + if (i2c_get_port(i2cconfig_args.port->ival[0], &i2c_port) != ESP_OK) { + return 1; + } + } + /* Check "--freq" option */ + if (i2cconfig_args.freq->count) { + i2c_frequency = i2cconfig_args.freq->ival[0]; + } + /* Check "--sda" option */ + i2c_gpio_sda = i2cconfig_args.sda->ival[0]; + /* Check "--scl" option */ + i2c_gpio_scl = i2cconfig_args.scl->ival[0]; + return 0; +} + +static void register_i2cconfig(void) +{ + i2cconfig_args.port = arg_int0(NULL, "port", "<0|1>", "Set the I2C bus port number"); + i2cconfig_args.freq = arg_int0(NULL, "freq", "", "Set the frequency(Hz) of I2C bus"); + i2cconfig_args.sda = arg_int1(NULL, "sda", "", "Set the gpio for I2C SDA"); + i2cconfig_args.scl = arg_int1(NULL, "scl", "", "Set the gpio for I2C SCL"); + i2cconfig_args.end = arg_end(2); + const esp_console_cmd_t i2cconfig_cmd = { + .command = "i2cconfig", + .help = "Config I2C bus", + .hint = NULL, + .func = &do_i2cconfig_cmd, + .argtable = &i2cconfig_args + }; + ESP_ERROR_CHECK(esp_console_cmd_register(&i2cconfig_cmd)); +} + +static int do_i2cdetect_cmd(int argc, char **argv) +{ + i2c_driver_install(i2c_port, I2C_MODE_MASTER, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0); + i2c_master_driver_initialize(); + uint8_t address; + printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\r\n"); + for (int i = 0; i < 128; i += 16) { + printf("%02x: ", i); + for (int j = 0; j < 16; j++) { + fflush(stdout); + address = i + j; + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (address << 1) | WRITE_BIT, ACK_CHECK_EN); + i2c_master_stop(cmd); + esp_err_t ret = i2c_master_cmd_begin(i2c_port, cmd, 50 / portTICK_PERIOD_MS); + i2c_cmd_link_delete(cmd); + if (ret == ESP_OK) { + printf("%02x ", address); + } else if (ret == ESP_ERR_TIMEOUT) { + printf("UU "); + } else { + printf("-- "); + } + } + printf("\r\n"); + } + + i2c_driver_delete(i2c_port); + return 0; +} + +static void register_i2cdetect(void) +{ + const esp_console_cmd_t i2cdetect_cmd = { + .command = "i2cdetect", + .help = "Scan I2C bus for devices", + .hint = NULL, + .func = &do_i2cdetect_cmd, + .argtable = NULL + }; + ESP_ERROR_CHECK(esp_console_cmd_register(&i2cdetect_cmd)); +} + +static struct { + struct arg_int *chip_address; + struct arg_int *register_address; + struct arg_int *data_length; + struct arg_end *end; +} i2cget_args; + +static int do_i2cget_cmd(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **)&i2cget_args); + if (nerrors != 0) { + arg_print_errors(stderr, i2cget_args.end, argv[0]); + return 0; + } + + /* Check chip address: "-c" option */ + int chip_addr = i2cget_args.chip_address->ival[0]; + /* Check register address: "-r" option */ + int data_addr = -1; + if (i2cget_args.register_address->count) { + data_addr = i2cget_args.register_address->ival[0]; + } + /* Check data length: "-l" option */ + int len = 1; + if (i2cget_args.data_length->count) { + len = i2cget_args.data_length->ival[0]; + } + uint8_t *data = malloc(len); + + i2c_driver_install(i2c_port, I2C_MODE_MASTER, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0); + i2c_master_driver_initialize(); + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + if (data_addr != -1) { + i2c_master_write_byte(cmd, chip_addr << 1 | WRITE_BIT, ACK_CHECK_EN); + i2c_master_write_byte(cmd, data_addr, ACK_CHECK_EN); + i2c_master_start(cmd); + } + i2c_master_write_byte(cmd, chip_addr << 1 | READ_BIT, ACK_CHECK_EN); + if (len > 1) { + i2c_master_read(cmd, data, len - 1, ACK_VAL); + } + i2c_master_read_byte(cmd, data + len - 1, NACK_VAL); + i2c_master_stop(cmd); + esp_err_t ret = i2c_master_cmd_begin(i2c_port, cmd, 1000 / portTICK_PERIOD_MS); + i2c_cmd_link_delete(cmd); + if (ret == ESP_OK) { + for (int i = 0; i < len; i++) { + printf("0x%02x ", data[i]); + if ((i + 1) % 16 == 0) { + printf("\r\n"); + } + } + if (len % 16) { + printf("\r\n"); + } + } else if (ret == ESP_ERR_TIMEOUT) { + ESP_LOGW(TAG, "Bus is busy"); + } else { + ESP_LOGW(TAG, "Read failed"); + } + free(data); + i2c_driver_delete(i2c_port); + return 0; +} + +static void register_i2cget(void) +{ + i2cget_args.chip_address = arg_int1("c", "chip", "", "Specify the address of the chip on that bus"); + i2cget_args.register_address = arg_int0("r", "register", "", "Specify the address on that chip to read from"); + i2cget_args.data_length = arg_int0("l", "length", "", "Specify the length to read from that data address"); + i2cget_args.end = arg_end(1); + const esp_console_cmd_t i2cget_cmd = { + .command = "i2cget", + .help = "Read registers visible through the I2C bus", + .hint = NULL, + .func = &do_i2cget_cmd, + .argtable = &i2cget_args + }; + ESP_ERROR_CHECK(esp_console_cmd_register(&i2cget_cmd)); +} + +static struct { + struct arg_int *chip_address; + struct arg_int *register_address; + struct arg_int *data; + struct arg_end *end; +} i2cset_args; + +static int do_i2cset_cmd(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **)&i2cset_args); + if (nerrors != 0) { + arg_print_errors(stderr, i2cset_args.end, argv[0]); + return 0; + } + + /* Check chip address: "-c" option */ + int chip_addr = i2cset_args.chip_address->ival[0]; + /* Check register address: "-r" option */ + int data_addr = 0; + if (i2cset_args.register_address->count) { + data_addr = i2cset_args.register_address->ival[0]; + } + /* Check data: "-d" option */ + int len = i2cset_args.data->count; + + i2c_driver_install(i2c_port, I2C_MODE_MASTER, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0); + i2c_master_driver_initialize(); + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, chip_addr << 1 | WRITE_BIT, ACK_CHECK_EN); + if (i2cset_args.register_address->count) { + i2c_master_write_byte(cmd, data_addr, ACK_CHECK_EN); + } + for (int i = 0; i < len; i++) { + i2c_master_write_byte(cmd, i2cset_args.data->ival[i], ACK_CHECK_EN); + } + i2c_master_stop(cmd); + esp_err_t ret = i2c_master_cmd_begin(i2c_port, cmd, 1000 / portTICK_PERIOD_MS); + i2c_cmd_link_delete(cmd); + if (ret == ESP_OK) { + ESP_LOGI(TAG, "Write OK"); + } else if (ret == ESP_ERR_TIMEOUT) { + ESP_LOGW(TAG, "Bus is busy"); + } else { + ESP_LOGW(TAG, "Write Failed"); + } + i2c_driver_delete(i2c_port); + return 0; +} + +static void register_i2cset(void) +{ + i2cset_args.chip_address = arg_int1("c", "chip", "", "Specify the address of the chip on that bus"); + i2cset_args.register_address = arg_int0("r", "register", "", "Specify the address on that chip to read from"); + i2cset_args.data = arg_intn(NULL, NULL, "", 0, 256, "Specify the data to write to that data address"); + i2cset_args.end = arg_end(2); + const esp_console_cmd_t i2cset_cmd = { + .command = "i2cset", + .help = "Set registers visible through the I2C bus", + .hint = NULL, + .func = &do_i2cset_cmd, + .argtable = &i2cset_args + }; + ESP_ERROR_CHECK(esp_console_cmd_register(&i2cset_cmd)); +} + +static struct { + struct arg_int *chip_address; + struct arg_int *size; + struct arg_end *end; +} i2cdump_args; + +static int do_i2cdump_cmd(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **)&i2cdump_args); + if (nerrors != 0) { + arg_print_errors(stderr, i2cdump_args.end, argv[0]); + return 0; + } + + /* Check chip address: "-c" option */ + int chip_addr = i2cdump_args.chip_address->ival[0]; + /* Check read size: "-s" option */ + int size = 1; + if (i2cdump_args.size->count) { + size = i2cdump_args.size->ival[0]; + } + if (size != 1 && size != 2 && size != 4) { + ESP_LOGE(TAG, "Wrong read size. Only support 1,2,4"); + return 1; + } + i2c_driver_install(i2c_port, I2C_MODE_MASTER, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0); + i2c_master_driver_initialize(); + uint8_t data_addr; + uint8_t data[4]; + int32_t block[16]; + printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f" + " 0123456789abcdef\r\n"); + for (int i = 0; i < 128; i += 16) { + printf("%02x: ", i); + for (int j = 0; j < 16; j += size) { + fflush(stdout); + data_addr = i + j; + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, chip_addr << 1 | WRITE_BIT, ACK_CHECK_EN); + i2c_master_write_byte(cmd, data_addr, ACK_CHECK_EN); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, chip_addr << 1 | READ_BIT, ACK_CHECK_EN); + if (size > 1) { + i2c_master_read(cmd, data, size - 1, ACK_VAL); + } + i2c_master_read_byte(cmd, data + size - 1, NACK_VAL); + i2c_master_stop(cmd); + esp_err_t ret = i2c_master_cmd_begin(i2c_port, cmd, 50 / portTICK_PERIOD_MS); + i2c_cmd_link_delete(cmd); + if (ret == ESP_OK) { + for (int k = 0; k < size; k++) { + printf("%02x ", data[k]); + block[j + k] = data[k]; + } + } else { + for (int k = 0; k < size; k++) { + printf("XX "); + block[j + k] = -1; + } + } + } + printf(" "); + for (int k = 0; k < 16; k++) { + if (block[k] < 0) { + printf("X"); + } + if ((block[k] & 0xff) == 0x00 || (block[k] & 0xff) == 0xff) { + printf("."); + } else if ((block[k] & 0xff) < 32 || (block[k] & 0xff) >= 127) { + printf("?"); + } else { + printf("%c", (char)(block[k] & 0xff)); + } + } + printf("\r\n"); + } + i2c_driver_delete(i2c_port); + return 0; +} + +static void register_i2cdump(void) +{ + i2cdump_args.chip_address = arg_int1("c", "chip", "", "Specify the address of the chip on that bus"); + i2cdump_args.size = arg_int0("s", "size", "", "Specify the size of each read"); + i2cdump_args.end = arg_end(1); + const esp_console_cmd_t i2cdump_cmd = { + .command = "i2cdump", + .help = "Examine registers visible through the I2C bus", + .hint = NULL, + .func = &do_i2cdump_cmd, + .argtable = &i2cdump_args + }; + ESP_ERROR_CHECK(esp_console_cmd_register(&i2cdump_cmd)); +} + +void register_i2ctools(void) +{ + register_i2cconfig(); + register_i2cdetect(); + register_i2cget(); + register_i2cset(); + register_i2cdump(); +} diff --git a/code/04.peripheral/basics/i2c_tools/main/cmd_i2ctools.h b/code/04.peripheral/basics/i2c_tools/main/cmd_i2ctools.h new file mode 100644 index 0000000..2bd3953 --- /dev/null +++ b/code/04.peripheral/basics/i2c_tools/main/cmd_i2ctools.h @@ -0,0 +1,20 @@ +/* cmd_i2ctools.h + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +void register_i2ctools(void); + +#ifdef __cplusplus +} +#endif diff --git a/code/04.peripheral/basics/i2c_tools/main/i2ctools_example_main.c b/code/04.peripheral/basics/i2c_tools/main/i2ctools_example_main.c new file mode 100644 index 0000000..7374b08 --- /dev/null +++ b/code/04.peripheral/basics/i2c_tools/main/i2ctools_example_main.c @@ -0,0 +1,80 @@ +/* i2c-tools example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#include +#include +#include "sdkconfig.h" +#include "esp_log.h" +#include "esp_console.h" +#include "esp_vfs_fat.h" +#include "cmd_system.h" +#include "cmd_i2ctools.h" + +static const char *TAG = "i2c-tools"; + +#if CONFIG_EXAMPLE_STORE_HISTORY + +#define MOUNT_PATH "/data" +#define HISTORY_PATH MOUNT_PATH "/history.txt" + +static void initialize_filesystem(void) +{ + static wl_handle_t wl_handle; + const esp_vfs_fat_mount_config_t mount_config = { + .max_files = 4, + .format_if_mount_failed = true + }; + esp_err_t err = esp_vfs_fat_spiflash_mount_rw_wl(MOUNT_PATH, "storage", &mount_config, &wl_handle); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to mount FATFS (%s)", esp_err_to_name(err)); + return; + } +} +#endif // CONFIG_EXAMPLE_STORE_HISTORY + +void app_main(void) +{ + esp_console_repl_t *repl = NULL; + esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT(); + +#if CONFIG_EXAMPLE_STORE_HISTORY + initialize_filesystem(); + repl_config.history_save_path = HISTORY_PATH; +#endif + repl_config.prompt = "i2c-tools>"; + + // install console REPL environment +#if CONFIG_ESP_CONSOLE_UART + esp_console_dev_uart_config_t uart_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_console_new_repl_uart(&uart_config, &repl_config, &repl)); +#elif CONFIG_ESP_CONSOLE_USB_CDC + esp_console_dev_usb_cdc_config_t cdc_config = ESP_CONSOLE_DEV_CDC_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_console_new_repl_usb_cdc(&cdc_config, &repl_config, &repl)); +#elif CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG + esp_console_dev_usb_serial_jtag_config_t usbjtag_config = ESP_CONSOLE_DEV_USB_SERIAL_JTAG_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_console_new_repl_usb_serial_jtag(&usbjtag_config, &repl_config, &repl)); +#endif + + register_i2ctools(); + + printf("\n ==============================================================\n"); + printf(" | Steps to Use i2c-tools |\n"); + printf(" | |\n"); + printf(" | 1. Try 'help', check all supported commands |\n"); + printf(" | 2. Try 'i2cconfig' to configure your I2C bus |\n"); + printf(" | 3. Try 'i2cdetect' to scan devices on the bus |\n"); + printf(" | 4. Try 'i2cget' to get the content of specific register |\n"); + printf(" | 5. Try 'i2cset' to set the value of specific register |\n"); + printf(" | 6. Try 'i2cdump' to dump all the register (Experiment) |\n"); + printf(" | |\n"); + printf(" ==============================================================\n\n"); + + // start console REPL + ESP_ERROR_CHECK(esp_console_start_repl(repl)); +} diff --git a/code/04.peripheral/basics/i2c_tools/partitions_example.csv b/code/04.peripheral/basics/i2c_tools/partitions_example.csv new file mode 100644 index 0000000..d4fe8bd --- /dev/null +++ b/code/04.peripheral/basics/i2c_tools/partitions_example.csv @@ -0,0 +1,6 @@ +# Name, Type, SubType, Offset, Size, Flags +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap +nvs, data, nvs, 0x9000, 0x6000, +phy_init, data, phy, 0xf000, 0x1000, +factory, app, factory, 0x10000, 1M, +storage, data, fat, , 528K, diff --git a/code/04.peripheral/basics/i2c_tools/sdkconfig.defaults b/code/04.peripheral/basics/i2c_tools/sdkconfig.defaults new file mode 100644 index 0000000..fc9a5ae --- /dev/null +++ b/code/04.peripheral/basics/i2c_tools/sdkconfig.defaults @@ -0,0 +1,17 @@ +# Reduce bootloader log verbosity +CONFIG_BOOTLOADER_LOG_LEVEL_WARN=y +CONFIG_BOOTLOADER_LOG_LEVEL=2 + +# Increase main task stack size +CONFIG_ESP_MAIN_TASK_STACK_SIZE=7168 + +# Enable filesystem +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_example.csv" +CONFIG_PARTITION_TABLE_FILENAME="partitions_example.csv" + +# Enable FreeRTOS stats formatting functions, needed for 'tasks' command +CONFIG_FREERTOS_USE_TRACE_FACILITY=y +CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS=y + +CONFIG_ESPTOOLPY_FLASHSIZE_2MB=y diff --git a/code/04.peripheral/basics/led_pwm/.gitignore b/code/04.peripheral/basics/led_pwm/.gitignore new file mode 100644 index 0000000..8da877b --- /dev/null +++ b/code/04.peripheral/basics/led_pwm/.gitignore @@ -0,0 +1,6 @@ +build +*managed_components +dependencies.lock +sdkconfig +sdkconfig.old + diff --git a/code/04.peripheral/basics/led_pwm/CMakeLists.txt b/code/04.peripheral/basics/led_pwm/CMakeLists.txt new file mode 100644 index 0000000..5b8c869 --- /dev/null +++ b/code/04.peripheral/basics/led_pwm/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(led_pwm) diff --git a/code/04.peripheral/basics/led_pwm/main/CMakeLists.txt b/code/04.peripheral/basics/led_pwm/main/CMakeLists.txt new file mode 100644 index 0000000..1786984 --- /dev/null +++ b/code/04.peripheral/basics/led_pwm/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "led_pwm.c" + INCLUDE_DIRS ".") diff --git a/code/04.peripheral/basics/led_pwm/main/led_pwm.c b/code/04.peripheral/basics/led_pwm/main/led_pwm.c new file mode 100644 index 0000000..0b21ba1 --- /dev/null +++ b/code/04.peripheral/basics/led_pwm/main/led_pwm.c @@ -0,0 +1,65 @@ +#include +#include "driver/ledc.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_err.h" + +#define LEDC_TIMER LEDC_TIMER_0 +#define LEDC_MODE LEDC_LOW_SPEED_MODE +#define LEDC_OUTPUT_IO (2) // Define the output GPIO +#define LEDC_CHANNEL LEDC_CHANNEL_0 +#define LEDC_DUTY_RES LEDC_TIMER_13_BIT // Set duty resolution to 13 bits +#define LEDC_DUTY (4096) // Set duty to 50%. (2 ** 13) * 50% = 4096 +#define LEDC_FREQUENCY (4000) // Frequency in Hertz. Set frequency at 4 kHz +#define FADE_TIME (2000) // Fade time in milliseconds + +static void example_ledc_init(void) +{ + // Prepare and then apply the LEDC PWM timer configuration + ledc_timer_config_t ledc_timer = { + .speed_mode = LEDC_MODE, + .duty_resolution = LEDC_DUTY_RES, + .timer_num = LEDC_TIMER, + .freq_hz = LEDC_FREQUENCY, // Set output frequency at 4 kHz + .clk_cfg = LEDC_AUTO_CLK + }; + ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer)); + + // Prepare and then apply the LEDC PWM channel configuration + ledc_channel_config_t ledc_channel = { + .speed_mode = LEDC_MODE, + .channel = LEDC_CHANNEL, + .timer_sel = LEDC_TIMER, + .intr_type = LEDC_INTR_DISABLE, + .gpio_num = LEDC_OUTPUT_IO, + .duty = 0, // Start with duty 0% + .hpoint = 0 + }; + ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel)); + + // Install LEDC fade function + ESP_ERROR_CHECK(ledc_fade_func_install(0)); +} + +void app_main(void) +{ + // Set the LEDC peripheral configuration + example_ledc_init(); + + while (1) + { + // Fade to 100% duty cycle within FADE_TIME milliseconds + ESP_ERROR_CHECK(ledc_set_fade_with_time(LEDC_MODE, LEDC_CHANNEL, LEDC_DUTY, FADE_TIME)); + ESP_ERROR_CHECK(ledc_fade_start(LEDC_MODE, LEDC_CHANNEL, LEDC_FADE_WAIT_DONE)); + + // Wait for the fade to complete + vTaskDelay(FADE_TIME / portTICK_PERIOD_MS); + + // Fade back to 0% duty cycle within FADE_TIME milliseconds + ESP_ERROR_CHECK(ledc_set_fade_with_time(LEDC_MODE, LEDC_CHANNEL, 0, FADE_TIME)); + ESP_ERROR_CHECK(ledc_fade_start(LEDC_MODE, LEDC_CHANNEL, LEDC_FADE_WAIT_DONE)); + + // Wait for the fade to complete + vTaskDelay(FADE_TIME / portTICK_PERIOD_MS); + } +} diff --git a/code/04.peripheral/basics/uart/.gitignore b/code/04.peripheral/basics/uart/.gitignore new file mode 100644 index 0000000..8da877b --- /dev/null +++ b/code/04.peripheral/basics/uart/.gitignore @@ -0,0 +1,6 @@ +build +*managed_components +dependencies.lock +sdkconfig +sdkconfig.old + diff --git a/code/04.peripheral/basics/uart/CMakeLists.txt b/code/04.peripheral/basics/uart/CMakeLists.txt new file mode 100644 index 0000000..930e642 --- /dev/null +++ b/code/04.peripheral/basics/uart/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(uart) diff --git a/code/04.peripheral/basics/uart/main/CMakeLists.txt b/code/04.peripheral/basics/uart/main/CMakeLists.txt new file mode 100644 index 0000000..ebabaeb --- /dev/null +++ b/code/04.peripheral/basics/uart/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "uart.c" + INCLUDE_DIRS ".") diff --git a/code/04.peripheral/basics/uart/main/uart.c b/code/04.peripheral/basics/uart/main/uart.c new file mode 100644 index 0000000..f2e8349 --- /dev/null +++ b/code/04.peripheral/basics/uart/main/uart.c @@ -0,0 +1,64 @@ +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" +#include "driver/uart.h" +#include "esp_err.h" +#include "string.h" + +#define TX_GPIO_NUM 17 +#define RX_GPIO_NUM 16 + +// 配置串口3 +void uart_config(void) { + const uart_port_t uart_num = UART_NUM_2; + + uart_config_t uart_config = { + .baud_rate = 115200, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + .rx_flow_ctrl_thresh = 122, + }; + + // 配置UART参数 + ESP_ERROR_CHECK(uart_param_config(uart_num, &uart_config)); + + // 设置UART引脚 + ESP_ERROR_CHECK(uart_set_pin(uart_num, TX_GPIO_NUM, RX_GPIO_NUM, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE)); + + // 安装UART驱动程序,不使用事件队列 + const int uart_buffer_size = (1024 * 2); + ESP_ERROR_CHECK(uart_driver_install(uart_num, uart_buffer_size, 0, 0, NULL, 0)); +} + +// 串口发送测试 +void uart_send_receive_demo(void) { + const uart_port_t uart_num = UART_NUM_2; + char* test_str = "This is a UART test string.\n"; + uint8_t data[128]; + + // 发送数据 + uart_write_bytes(uart_num, test_str, strlen(test_str)); + + while(1){ + vTaskDelay(1); + // 等待数据接收 + int length = 0; + ESP_ERROR_CHECK(uart_get_buffered_data_len(uart_num, (size_t*)&length)); + if(length > 0) { + int read_len = uart_read_bytes(uart_num, data, length, pdMS_TO_TICKS(1000)); + if(read_len > 0) { + // 输出接收到的数据 + printf("Received: %.*s\n", read_len, data); + } + } + } + +} + + +void app_main(void) { + uart_config(); + uart_send_receive_demo(); +} diff --git a/code/04.peripheral/storage/flash_fatfs/.gitignore b/code/04.peripheral/storage/flash_fatfs/.gitignore new file mode 100644 index 0000000..8da877b --- /dev/null +++ b/code/04.peripheral/storage/flash_fatfs/.gitignore @@ -0,0 +1,6 @@ +build +*managed_components +dependencies.lock +sdkconfig +sdkconfig.old + diff --git a/code/04.peripheral/storage/flash_fatfs/.gitignore copy b/code/04.peripheral/storage/flash_fatfs/.gitignore copy new file mode 100644 index 0000000..ee2dc29 --- /dev/null +++ b/code/04.peripheral/storage/flash_fatfs/.gitignore copy @@ -0,0 +1,6 @@ +*build +*managed_components +dependencies.lock +sdkconfig +sdkconfig.old + diff --git a/code/04.peripheral/storage/flash_fatfs/CMakeLists.txt b/code/04.peripheral/storage/flash_fatfs/CMakeLists.txt new file mode 100644 index 0000000..b325dda --- /dev/null +++ b/code/04.peripheral/storage/flash_fatfs/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(flash_fatfs) diff --git a/code/04.peripheral/storage/flash_fatfs/fatfs_image/hello.txt b/code/04.peripheral/storage/flash_fatfs/fatfs_image/hello.txt new file mode 100644 index 0000000..b7d3448 --- /dev/null +++ b/code/04.peripheral/storage/flash_fatfs/fatfs_image/hello.txt @@ -0,0 +1 @@ +11111111111111111111111111111222222222 diff --git a/code/04.peripheral/storage/flash_fatfs/main/CMakeLists.txt b/code/04.peripheral/storage/flash_fatfs/main/CMakeLists.txt new file mode 100644 index 0000000..5796529 --- /dev/null +++ b/code/04.peripheral/storage/flash_fatfs/main/CMakeLists.txt @@ -0,0 +1,5 @@ +idf_component_register(SRCS "flash_fatfs.c" + INCLUDE_DIRS ".") + +set(image ../fatfs_image) +fatfs_create_spiflash_image(storage ${image} FLASH_IN_PROJECT) diff --git a/code/04.peripheral/storage/flash_fatfs/main/flash_fatfs-backups.c b/code/04.peripheral/storage/flash_fatfs/main/flash_fatfs-backups.c new file mode 100644 index 0000000..45aa680 --- /dev/null +++ b/code/04.peripheral/storage/flash_fatfs/main/flash_fatfs-backups.c @@ -0,0 +1,85 @@ +// 演示读写文件 + +#include +#include +#include +#include "esp_flash.h" +#include "esp_vfs.h" +#include "esp_vfs_fat.h" +#include "esp_system.h" + +static const char *TAG = "FAT"; + +// Handle of the wear levelling library instance +static wl_handle_t s_wl_handle = WL_INVALID_HANDLE; + +// Mount path for the partition +const char *base_path = "/fatfs_image"; + +// Mount FATFS partition +static bool mount_fatfs(const char* partition_label) +{ + ESP_LOGI(TAG, "Mounting FAT filesystem"); + const esp_vfs_fat_mount_config_t mount_config = { + .max_files = 4, + .format_if_mount_failed = true, + .allocation_unit_size = CONFIG_WL_SECTOR_SIZE + }; + esp_err_t err = esp_vfs_fat_spiflash_mount_rw_wl(base_path, partition_label, &mount_config, &s_wl_handle); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to mount FATFS (%s)", esp_err_to_name(err)); + return false; + } + return true; +} + +void app_main(void) +{ + const char *partition_label = "storage"; + // Initialize FAT FS in the partition + if (!mount_fatfs(partition_label)) { + return; + } + + // Print FAT FS size information + uint64_t bytes_total, bytes_free; + esp_vfs_fat_info(base_path, &bytes_total, &bytes_free); + ESP_LOGI(TAG, "FAT FS: %" PRIu64 " kB total, %" PRIu64 " kB free", bytes_total / 1024, bytes_free / 1024); + + Create a file in FAT FS + ESP_LOGI(TAG, "Opening file"); + FILE *f = fopen("/fatfs_image/hello.txt", "wb"); + if (f == NULL) { + ESP_LOGE(TAG, "Failed to open file for writing"); + return; + } + fprintf(f, "fat文件系统测试 %s\n", "hollo world!"); + fclose(f); + ESP_LOGI(TAG, "File written"); + + // Open file for reading + ESP_LOGI(TAG, "Reading file"); + f = fopen("/fatfs_image/hello.txt", "rb"); + if (f == NULL) { + ESP_LOGE(TAG, "Failed to open file for reading"); + return; + } + char line[128]; + fgets(line, sizeof(line), f); + fclose(f); + // strip newline + char *pos = strchr(line, '\n'); + if (pos) { + *pos = '\0'; + } + ESP_LOGI(TAG, "Read from file: '%s'", line); + // Unmount FAT FS + ESP_LOGI(TAG, "Unmounting FAT filesystem"); + esp_err_t unmount_err = esp_vfs_fat_spiflash_unmount_rw_wl(base_path, s_wl_handle); + if (unmount_err != ESP_OK) { + ESP_LOGE(TAG, "Failed to unmount FATFS (%s)", esp_err_to_name(unmount_err)); + return; + } +} + + diff --git a/code/04.peripheral/storage/flash_fatfs/main/flash_fatfs.c b/code/04.peripheral/storage/flash_fatfs/main/flash_fatfs.c new file mode 100644 index 0000000..1c9eacc --- /dev/null +++ b/code/04.peripheral/storage/flash_fatfs/main/flash_fatfs.c @@ -0,0 +1,73 @@ +#include +#include +#include +#include "esp_flash.h" +#include "esp_vfs.h" +#include "esp_vfs_fat.h" +#include "esp_system.h" + +static const char *TAG = "FAT"; + +// Handle of the wear levelling library instance +static wl_handle_t s_wl_handle = WL_INVALID_HANDLE; + +// Mount path for the partition +const char *base_path = "/fatfs_image"; + +// Mount FATFS partition +static bool mount_fatfs(const char* partition_label) +{ + ESP_LOGI(TAG, "Mounting FAT filesystem"); + const esp_vfs_fat_mount_config_t mount_config = { + .max_files = 4, + .format_if_mount_failed = true, + .allocation_unit_size = CONFIG_WL_SECTOR_SIZE + }; + esp_err_t err = esp_vfs_fat_spiflash_mount_rw_wl(base_path, partition_label, &mount_config, &s_wl_handle); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to mount FATFS (%s)", esp_err_to_name(err)); + return false; + } + return true; +} + +void app_main(void) +{ + const char *partition_label = "storage"; + // Initialize FAT FS in the partition + if (!mount_fatfs(partition_label)) { + return; + } + + // Print FAT FS size information + uint64_t bytes_total, bytes_free; + esp_vfs_fat_info(base_path, &bytes_total, &bytes_free); + ESP_LOGI(TAG, "FAT FS: %" PRIu64 " kB total, %" PRIu64 " kB free", bytes_total / 1024, bytes_free / 1024); + + // 读取写入的镜像文件 + // Open file for reading + ESP_LOGI(TAG, "Reading file"); + FILE *f = fopen("/fatfs_image/hello.txt", "rb"); + if (f == NULL) { + ESP_LOGE(TAG, "Failed to open file for reading"); + return; + } + char line[128]; + fgets(line, sizeof(line), f); + fclose(f); + // strip newline + char *pos = strchr(line, '\n'); + if (pos) { + *pos = '\0'; + } + ESP_LOGI(TAG, "Read from file: '%s'", line); + // Unmount FAT FS + ESP_LOGI(TAG, "Unmounting FAT filesystem"); + esp_err_t unmount_err = esp_vfs_fat_spiflash_unmount_rw_wl(base_path, s_wl_handle); + if (unmount_err != ESP_OK) { + ESP_LOGE(TAG, "Failed to unmount FATFS (%s)", esp_err_to_name(unmount_err)); + return; + } +} + + diff --git a/code/04.peripheral/storage/flash_fatfs/partitions.csv b/code/04.peripheral/storage/flash_fatfs/partitions.csv new file mode 100644 index 0000000..3ddb1e4 --- /dev/null +++ b/code/04.peripheral/storage/flash_fatfs/partitions.csv @@ -0,0 +1,7 @@ +# ESP-IDF Partition Table +# Name, Type, SubType, Offset, Size, Flags +nvs, data, nvs, 0x9000, 0x4000, +phy_init, data, phy, 0xf000, 0x1000, +factory, app, factory, 0x10000, 1M, +storage, data, fat, 0x110000, 1M, + diff --git a/code/04.peripheral/storage/flash_spiffs/.gitignore b/code/04.peripheral/storage/flash_spiffs/.gitignore new file mode 100644 index 0000000..8da877b --- /dev/null +++ b/code/04.peripheral/storage/flash_spiffs/.gitignore @@ -0,0 +1,6 @@ +build +*managed_components +dependencies.lock +sdkconfig +sdkconfig.old + diff --git a/code/04.peripheral/storage/flash_spiffs/CMakeLists.txt b/code/04.peripheral/storage/flash_spiffs/CMakeLists.txt new file mode 100644 index 0000000..c35429d --- /dev/null +++ b/code/04.peripheral/storage/flash_spiffs/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(flash_spiffs) diff --git a/code/04.peripheral/storage/flash_spiffs/main/CMakeLists.txt b/code/04.peripheral/storage/flash_spiffs/main/CMakeLists.txt new file mode 100644 index 0000000..ec4b876 --- /dev/null +++ b/code/04.peripheral/storage/flash_spiffs/main/CMakeLists.txt @@ -0,0 +1,8 @@ +idf_component_register(SRCS "flash_spiffs.c" + INCLUDE_DIRS ".") + +# Create a SPIFFS image from the contents of the 'spiffs_image' directory +# that fits the partition named 'storage'. FLASH_IN_PROJECT indicates that +# the generated image should be flashed when the entire project is flashed to +# the target with 'idf.py -p PORT flash'. +spiffs_create_partition_image(storage ../spiffs_image FLASH_IN_PROJECT) diff --git a/code/04.peripheral/storage/flash_spiffs/main/flash_spiffs.c b/code/04.peripheral/storage/flash_spiffs/main/flash_spiffs.c new file mode 100644 index 0000000..9c5d1a1 --- /dev/null +++ b/code/04.peripheral/storage/flash_spiffs/main/flash_spiffs.c @@ -0,0 +1,122 @@ +#include +#include +#include +#include +#include "esp_err.h" +#include "esp_log.h" +#include "esp_spiffs.h" +#include "mbedtls/md5.h" + +static const char *TAG = "example"; + +static void read_hello_txt(void) +{ + ESP_LOGI(TAG, "Reading hello.txt"); + + // Open for reading hello.txt + FILE* f = fopen("/spiffs/hello.txt", "r"); + if (f == NULL) { + ESP_LOGE(TAG, "Failed to open hello.txt"); + return; + } + + char buf[64]; + memset(buf, 0, sizeof(buf)); + fread(buf, 1, sizeof(buf), f); + fclose(f); + + // Display the read contents from the file + ESP_LOGI(TAG, "Read from hello.txt: %s", buf); +} + +static void compute_alice_txt_md5(void) +{ + ESP_LOGI(TAG, "Computing alice.txt MD5 hash"); + + // The file alice.txt lives under a subdirectory, though SPIFFS itself is flat + FILE* f = fopen("/spiffs/sub/alice.txt", "r"); + if (f == NULL) { + ESP_LOGE(TAG, "Failed to open alice.txt"); + return; + } + + // Read file and compute the digest chunk by chunk + #define MD5_MAX_LEN 16 + + char buf[64]; + mbedtls_md5_context ctx; + unsigned char digest[MD5_MAX_LEN]; + + mbedtls_md5_init(&ctx); + mbedtls_md5_starts(&ctx); + + size_t read; + + do { + read = fread((void*) buf, 1, sizeof(buf), f); + mbedtls_md5_update(&ctx, (unsigned const char*) buf, read); + } while(read == sizeof(buf)); + + mbedtls_md5_finish(&ctx, digest); + + // Create a string of the digest + char digest_str[MD5_MAX_LEN * 2]; + + for (int i = 0; i < MD5_MAX_LEN; i++) { + sprintf(&digest_str[i * 2], "%02x", (unsigned int)digest[i]); + } + + // For reference, MD5 should be deeb71f585cbb3ae5f7976d5127faf2a + ESP_LOGI(TAG, "Computed MD5 hash of alice.txt: %s", digest_str); + + fclose(f); +} + +void app_main(void) +{ + ESP_LOGI(TAG, "Initializing SPIFFS"); + + esp_vfs_spiffs_conf_t conf = { + .base_path = "/spiffs", + .partition_label = NULL, + .max_files = 5, + .format_if_mount_failed = false + }; + + // Use settings defined above to initialize and mount SPIFFS filesystem. + // Note: esp_vfs_spiffs_register is an all-in-one convenience function. + esp_err_t ret = esp_vfs_spiffs_register(&conf); + + if (ret != ESP_OK) { + if (ret == ESP_FAIL) { + ESP_LOGE(TAG, "Failed to mount or format filesystem"); + } else if (ret == ESP_ERR_NOT_FOUND) { + ESP_LOGE(TAG, "Failed to find SPIFFS partition"); + } else { + ESP_LOGE(TAG, "Failed to initialize SPIFFS (%s)", esp_err_to_name(ret)); + } + return; + } + + size_t total = 0, used = 0; + ret = esp_spiffs_info(NULL, &total, &used); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to get SPIFFS partition information (%s)", esp_err_to_name(ret)); + } else { + ESP_LOGI(TAG, "Partition size: total: %d, used: %d", total, used); + } + + /* The following calls demonstrate reading files from the generated SPIFFS + * image. The images should contain the same files and contents as the spiffs_image directory. + */ + + // Read and display the contents of a small text file (hello.txt) + read_hello_txt(); + + // Compute and display the MD5 hash of a large text file (alice.txt) + compute_alice_txt_md5(); + + // All done, unmount partition and disable SPIFFS + esp_vfs_spiffs_unregister(NULL); + ESP_LOGI(TAG, "SPIFFS unmounted"); +} diff --git a/code/04.peripheral/storage/flash_spiffs/partitions.csv b/code/04.peripheral/storage/flash_spiffs/partitions.csv new file mode 100644 index 0000000..597fcdd --- /dev/null +++ b/code/04.peripheral/storage/flash_spiffs/partitions.csv @@ -0,0 +1,7 @@ +# ESP-IDF Partition Table +# Name, Type, SubType, Offset, Size, Flags +nvs, data, nvs, 0x9000, 0x4000, +phy_init, data, phy, 0xf000, 0x1000, +factory, app, factory, 0x10000, 1M, +storage, data, spiffs, , 0xF0000, + diff --git a/code/04.peripheral/storage/flash_spiffs/spiffs_image/hello.txt b/code/04.peripheral/storage/flash_spiffs/spiffs_image/hello.txt new file mode 100644 index 0000000..980a0d5 --- /dev/null +++ b/code/04.peripheral/storage/flash_spiffs/spiffs_image/hello.txt @@ -0,0 +1 @@ +Hello World! diff --git a/code/04.peripheral/storage/flash_spiffs/spiffs_image/sub/alice.txt b/code/04.peripheral/storage/flash_spiffs/spiffs_image/sub/alice.txt new file mode 100644 index 0000000..62c7a8c --- /dev/null +++ b/code/04.peripheral/storage/flash_spiffs/spiffs_image/sub/alice.txt @@ -0,0 +1,21 @@ +Project Gutenberg’s Alice’s Adventures in Wonderland, by Lewis Carroll + +This eBook is for the use of anyone anywhere at no cost and with +almost no restrictions whatsoever. You may copy it, give it away or +re-use it under the terms of the Project Gutenberg License included +with this eBook or online at www.gutenberg.org + + +Title: Alice’s Adventures in Wonderland + +Author: Lewis Carroll + +Posting Date: June 25, 2008 [EBook #11] +Release Date: March, 1994 +Last Updated: October 6, 2016 + +Language: English + +Character set encoding: UTF-8 + +*** START OF THIS PROJECT GUTENBERG EBOOK ALICE’S ADVENTURES IN WONDERLAND *** diff --git a/code/04.peripheral/storage/nvs/.gitignore b/code/04.peripheral/storage/nvs/.gitignore new file mode 100644 index 0000000..8da877b --- /dev/null +++ b/code/04.peripheral/storage/nvs/.gitignore @@ -0,0 +1,6 @@ +build +*managed_components +dependencies.lock +sdkconfig +sdkconfig.old + diff --git a/code/04.peripheral/storage/nvs/CMakeLists.txt b/code/04.peripheral/storage/nvs/CMakeLists.txt new file mode 100644 index 0000000..dcf6b76 --- /dev/null +++ b/code/04.peripheral/storage/nvs/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(nvs) diff --git a/code/04.peripheral/storage/nvs/main/CMakeLists.txt b/code/04.peripheral/storage/nvs/main/CMakeLists.txt new file mode 100644 index 0000000..a8c63a3 --- /dev/null +++ b/code/04.peripheral/storage/nvs/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "nvs.c" + INCLUDE_DIRS ".") diff --git a/code/04.peripheral/storage/nvs/main/nvs.c b/code/04.peripheral/storage/nvs/main/nvs.c new file mode 100644 index 0000000..c138029 --- /dev/null +++ b/code/04.peripheral/storage/nvs/main/nvs.c @@ -0,0 +1,75 @@ +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_system.h" +#include "nvs_flash.h" +#include "nvs.h" + +void app_main(void) +{ + // Initialize NVS + esp_err_t err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { + // NVS partition was truncated and needs to be erased + // Retry nvs_flash_init + ESP_ERROR_CHECK(nvs_flash_erase()); + err = nvs_flash_init(); + } + ESP_ERROR_CHECK( err ); + + // Open + printf("\n"); + printf("Opening Non-Volatile Storage (NVS) handle... "); + nvs_handle_t my_handle; + err = nvs_open("storage", NVS_READWRITE, &my_handle); + if (err != ESP_OK) { + printf("Error (%s) opening NVS handle!\n", esp_err_to_name(err)); + } else { + printf("Done\n"); + + // Read + printf("Reading restart counter from NVS ... "); + int32_t restart_counter = 0; // value will default to 0, if not set yet in NVS + err = nvs_get_i32(my_handle, "restart_counter", &restart_counter); + switch (err) { + case ESP_OK: + printf("Done\n"); + printf("Restart counter = %" PRIu32 "\n", restart_counter); + break; + case ESP_ERR_NVS_NOT_FOUND: + printf("The value is not initialized yet!\n"); + break; + default : + printf("Error (%s) reading!\n", esp_err_to_name(err)); + } + + // Write + printf("Updating restart counter in NVS ... "); + restart_counter++; + err = nvs_set_i32(my_handle, "restart_counter", restart_counter); + printf((err != ESP_OK) ? "Failed!\n" : "Done\n"); + + // Commit written value. + // After setting any values, nvs_commit() must be called to ensure changes are written + // to flash storage. Implementations may write to storage at other times, + // but this is not guaranteed. + printf("Committing updates in NVS ... "); + err = nvs_commit(my_handle); + printf((err != ESP_OK) ? "Failed!\n" : "Done\n"); + + // Close + nvs_close(my_handle); + } + + printf("\n"); + + // Restart module + for (int i = 10; i >= 0; i--) { + printf("Restarting in %d seconds...\n", i); + vTaskDelay(1000 / portTICK_PERIOD_MS); + } + printf("Restarting now.\n"); + fflush(stdout); + esp_restart(); +} diff --git a/code/04.peripheral/storage/partition/.gitignore b/code/04.peripheral/storage/partition/.gitignore new file mode 100644 index 0000000..8da877b --- /dev/null +++ b/code/04.peripheral/storage/partition/.gitignore @@ -0,0 +1,6 @@ +build +*managed_components +dependencies.lock +sdkconfig +sdkconfig.old + diff --git a/code/04.peripheral/storage/partition/CMakeLists.txt b/code/04.peripheral/storage/partition/CMakeLists.txt new file mode 100644 index 0000000..8124cb8 --- /dev/null +++ b/code/04.peripheral/storage/partition/CMakeLists.txt @@ -0,0 +1,6 @@ +# The following lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(partition) diff --git a/code/04.peripheral/storage/partition/main/CMakeLists.txt b/code/04.peripheral/storage/partition/main/CMakeLists.txt new file mode 100644 index 0000000..1be1888 --- /dev/null +++ b/code/04.peripheral/storage/partition/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "partition.c" + INCLUDE_DIRS "") diff --git a/code/04.peripheral/storage/partition/main/partition.c b/code/04.peripheral/storage/partition/main/partition.c new file mode 100644 index 0000000..e7b27a8 --- /dev/null +++ b/code/04.peripheral/storage/partition/main/partition.c @@ -0,0 +1,51 @@ +/* + * SPDX-FileCopyrightText: 2010-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: CC0-1.0 + */ + +#include +#include +#include "sdkconfig.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_chip_info.h" +#include "esp_flash.h" + +void app_main(void) +{ + printf("Hello world!\n"); + + /* Print chip information */ + esp_chip_info_t chip_info; + uint32_t flash_size; + esp_chip_info(&chip_info); + printf("This is %s chip with %d CPU core(s), %s%s%s%s, ", + CONFIG_IDF_TARGET, + chip_info.cores, + (chip_info.features & CHIP_FEATURE_WIFI_BGN) ? "WiFi/" : "", + (chip_info.features & CHIP_FEATURE_BT) ? "BT" : "", + (chip_info.features & CHIP_FEATURE_BLE) ? "BLE" : "", + (chip_info.features & CHIP_FEATURE_IEEE802154) ? ", 802.15.4 (Zigbee/Thread)" : ""); + + unsigned major_rev = chip_info.revision / 100; + unsigned minor_rev = chip_info.revision % 100; + printf("silicon revision v%d.%d, ", major_rev, minor_rev); + if(esp_flash_get_size(NULL, &flash_size) != ESP_OK) { + printf("Get flash size failed"); + return; + } + + printf("%" PRIu32 "MB %s flash\n", flash_size / (uint32_t)(1024 * 1024), + (chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external"); + + printf("Minimum free heap size: %" PRIu32 " bytes\n", esp_get_minimum_free_heap_size()); + + for (int i = 10; i >= 0; i--) { + printf("Restarting in %d seconds...\n", i); + vTaskDelay(1000 / portTICK_PERIOD_MS); + } + printf("Restarting now.\n"); + fflush(stdout); + esp_restart(); +} diff --git a/code/04.peripheral/storage/partition/partitions.csv b/code/04.peripheral/storage/partition/partitions.csv new file mode 100644 index 0000000..28ea819 --- /dev/null +++ b/code/04.peripheral/storage/partition/partitions.csv @@ -0,0 +1,8 @@ +# ESP-IDF Partition Table +# Name, Type, SubType, Offset, Size, Flags +nvs, data, nvs, 0x9000, 0x4000, +otadata, data, ota, 0xd000, 0x2000, +phy_init, data, phy, 0xf000, 0x1000, +factory, app, factory, 0x10000, 1M, +ota_0, app, ota_0, 0x110000, 1M, + diff --git a/code/04.peripheral/storage/partition/sdkconfig.ci b/code/04.peripheral/storage/partition/sdkconfig.ci new file mode 100644 index 0000000..e69de29 diff --git a/code/04.peripheral/storage/sdmmc/.gitignore b/code/04.peripheral/storage/sdmmc/.gitignore new file mode 100644 index 0000000..8da877b --- /dev/null +++ b/code/04.peripheral/storage/sdmmc/.gitignore @@ -0,0 +1,6 @@ +build +*managed_components +dependencies.lock +sdkconfig +sdkconfig.old + diff --git a/code/04.peripheral/storage/sdmmc/CMakeLists.txt b/code/04.peripheral/storage/sdmmc/CMakeLists.txt new file mode 100644 index 0000000..664d458 --- /dev/null +++ b/code/04.peripheral/storage/sdmmc/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(main) diff --git a/code/04.peripheral/storage/sdmmc/main/CMakeLists.txt b/code/04.peripheral/storage/sdmmc/main/CMakeLists.txt new file mode 100644 index 0000000..cdde10c --- /dev/null +++ b/code/04.peripheral/storage/sdmmc/main/CMakeLists.txt @@ -0,0 +1,9 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") + +# 只有ESP32 和ESP32S3支持SDMMC +if(NOT CONFIG_SOC_SDMMC_HOST_SUPPORTED) + fail_at_build_time(sdmmc "" + "Only ESP32 and ESP32-S3 targets are supported." + "Please refer README.md for more details") +endif() diff --git a/code/04.peripheral/storage/sdmmc/main/Kconfig.projbuild b/code/04.peripheral/storage/sdmmc/main/Kconfig.projbuild new file mode 100644 index 0000000..3b4b8bc --- /dev/null +++ b/code/04.peripheral/storage/sdmmc/main/Kconfig.projbuild @@ -0,0 +1,63 @@ +menu "SD/MMC Example Configuration" + + config EXAMPLE_FORMAT_IF_MOUNT_FAILED + bool "Format the card if mount failed" + default n + help + If this config item is set, format_if_mount_failed will be set to true and the card will be formatted if + the mount has failed. + + choice EXAMPLE_SDMMC_BUS_WIDTH + prompt "SD/MMC bus width" + default EXAMPLE_SDMMC_BUS_WIDTH_4 + help + Select the bus width of SD or MMC interface. + Note that even if 1 line mode is used, D3 pin of the SD card must have a pull-up resistor connected. + Otherwise the card may enter SPI mode, the only way to recover from which is to cycle power to the card. + + config EXAMPLE_SDMMC_BUS_WIDTH_4 + bool "4 lines (D0 - D3)" + + config EXAMPLE_SDMMC_BUS_WIDTH_1 + bool "1 line (D0)" + endchoice + + if SOC_SDMMC_USE_GPIO_MATRIX + + config EXAMPLE_PIN_CMD + int "CMD GPIO number" + default 35 if IDF_TARGET_ESP32S3 + default 44 if IDF_TARGET_ESP32P4 + + config EXAMPLE_PIN_CLK + int "CLK GPIO number" + default 36 if IDF_TARGET_ESP32S3 + default 43 if IDF_TARGET_ESP32P4 + + config EXAMPLE_PIN_D0 + int "D0 GPIO number" + default 37 if IDF_TARGET_ESP32S3 + default 39 if IDF_TARGET_ESP32P4 + + if EXAMPLE_SDMMC_BUS_WIDTH_4 + + config EXAMPLE_PIN_D1 + int "D1 GPIO number" + default 38 if IDF_TARGET_ESP32S3 + default 40 if IDF_TARGET_ESP32P4 + + config EXAMPLE_PIN_D2 + int "D2 GPIO number" + default 33 if IDF_TARGET_ESP32S3 + default 41 if IDF_TARGET_ESP32P4 + + config EXAMPLE_PIN_D3 + int "D3 GPIO number" + default 34 if IDF_TARGET_ESP32S3 + default 42 if IDF_TARGET_ESP32P4 + + endif # EXAMPLE_SDMMC_BUS_WIDTH_4 + + endif # SOC_SDMMC_USE_GPIO_MATRIX + +endmenu diff --git a/code/04.peripheral/storage/sdmmc/main/main.c b/code/04.peripheral/storage/sdmmc/main/main.c new file mode 100644 index 0000000..1e053db --- /dev/null +++ b/code/04.peripheral/storage/sdmmc/main/main.c @@ -0,0 +1,217 @@ + +// This example uses SDMMC peripheral to communicate with SD card. +#include +#include +#include +#include "esp_vfs_fat.h" +#include "sdmmc_cmd.h" +#include "driver/sdmmc_host.h" + +#define EXAMPLE_MAX_CHAR_SIZE 64 + + +static const char *TAG = "example"; + +#define MOUNT_POINT "/sdcard" + +static esp_err_t s_example_write_file(const char *path, char *data) +{ + ESP_LOGI(TAG, "Opening file %s", path); + FILE *f = fopen(path, "w"); + if (f == NULL) + { + ESP_LOGE(TAG, "Failed to open file for writing"); + return ESP_FAIL; + } + fprintf(f, data); + fclose(f); + ESP_LOGI(TAG, "File written"); + + return ESP_OK; +} + +static esp_err_t s_example_read_file(const char *path) +{ + ESP_LOGI(TAG, "Reading file %s", path); + FILE *f = fopen(path, "r"); + if (f == NULL) + { + ESP_LOGE(TAG, "Failed to open file for reading"); + return ESP_FAIL; + } + char line[EXAMPLE_MAX_CHAR_SIZE]; + fgets(line, sizeof(line), f); + fclose(f); + + // strip newline + char *pos = strchr(line, '\n'); + if (pos) + { + *pos = '\0'; + } + ESP_LOGI(TAG, "Read from file: '%s'", line); + + return ESP_OK; +} + +void app_main(void) +{ + esp_err_t ret; + + // Options for mounting the filesystem. + // If format_if_mount_failed is set to true, SD card will be partitioned and + // formatted in case when mounting fails. + esp_vfs_fat_sdmmc_mount_config_t mount_config = { + // 此选项用于开关SD卡挂载失败后是否格式化 +#ifdef CONFIG_EXAMPLE_FORMAT_IF_MOUNT_FAILED + .format_if_mount_failed = true, +#else + .format_if_mount_failed = false, +#endif // EXAMPLE_FORMAT_IF_MOUNT_FAILED + .max_files = 5, + .allocation_unit_size = 16 * 1024}; + + sdmmc_card_t *card; + const char mount_point[] = MOUNT_POINT; + ESP_LOGI(TAG, "Initializing SD card"); + + // Use settings defined above to initialize SD card and mount FAT filesystem. + // Note: esp_vfs_fat_sdmmc/sdspi_mount is all-in-one convenience functions. + // Please check its source code and implement error recovery when developing + // production applications. + + ESP_LOGI(TAG, "Using SDMMC peripheral"); + + // By default, SD card frequency is initialized to SDMMC_FREQ_DEFAULT (20MHz) + // For setting a specific frequency, use host.max_freq_khz (range 400kHz - 40MHz for SDMMC) + // Example: for fixed frequency of 10MHz, use host.max_freq_khz = 10000; + sdmmc_host_t host = SDMMC_HOST_DEFAULT(); + + // This initializes the slot without card detect (CD) and write protect (WP) signals. + // Modify slot_config.gpio_cd and slot_config.gpio_wp if your board has these signals. + sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT(); + + // Set bus width to use: +#ifdef CONFIG_EXAMPLE_SDMMC_BUS_WIDTH_4 + slot_config.width = 4; +#else + slot_config.width = 1; +#endif + + + // 使用ESP32的话,下面部分无用,SD卡对应的接口是唯一的,无法自定义 + // 可以参考:https://github.com/espressif/esp-idf/tree/master/examples/storage/sd_card/sdmmc#pin-assignments-for-esp32-s3 + // On chips where the GPIOs used for SD card can be configured, set them in + // the slot_config structure: + #ifdef CONFIG_SOC_SDMMC_USE_GPIO_MATRIX + slot_config.clk = CONFIG_EXAMPLE_PIN_CLK; + slot_config.cmd = CONFIG_EXAMPLE_PIN_CMD; + slot_config.d0 = CONFIG_EXAMPLE_PIN_D0; + #ifdef CONFIG_EXAMPLE_SDMMC_BUS_WIDTH_4 + slot_config.d1 = CONFIG_EXAMPLE_PIN_D1; + slot_config.d2 = CONFIG_EXAMPLE_PIN_D2; + slot_config.d3 = CONFIG_EXAMPLE_PIN_D3; + #endif // CONFIG_EXAMPLE_SDMMC_BUS_WIDTH_4 + #endif // CONFIG_SOC_SDMMC_USE_GPIO_MATRIX + + // Enable internal pullups on enabled pins. The internal pullups + // are insufficient however, please make sure 10k external pullups are + // connected on the bus. This is for debug / example purpose only. + slot_config.flags |= SDMMC_SLOT_FLAG_INTERNAL_PULLUP; + + ESP_LOGI(TAG, "Mounting filesystem"); + ret = esp_vfs_fat_sdmmc_mount(mount_point, &host, &slot_config, &mount_config, &card); + + if (ret != ESP_OK) + { + if (ret == ESP_FAIL) + { + ESP_LOGE(TAG, "Failed to mount filesystem. " + "If you want the card to be formatted, set the EXAMPLE_FORMAT_IF_MOUNT_FAILED menuconfig option."); + } + else + { + ESP_LOGE(TAG, "Failed to initialize the card (%s). " + "Make sure SD card lines have pull-up resistors in place.", + esp_err_to_name(ret)); + } + return; + } + ESP_LOGI(TAG, "Filesystem mounted"); + + // Card has been initialized, print its properties + sdmmc_card_print_info(stdout, card); + + // Use POSIX and C standard library functions to work with files: + + // First create a file. + const char *file_hello = MOUNT_POINT "/hello.txt"; + char data[EXAMPLE_MAX_CHAR_SIZE]; + snprintf(data, EXAMPLE_MAX_CHAR_SIZE, "%s %s!\n", "Hello", card->cid.name); + ret = s_example_write_file(file_hello, data); + if (ret != ESP_OK) + { + return; + } + + const char *file_foo = MOUNT_POINT "/foo.txt"; + // Check if destination file exists before renaming + struct stat st; + if (stat(file_foo, &st) == 0) + { + // Delete it if it exists + unlink(file_foo); + } + + // Rename original file + ESP_LOGI(TAG, "Renaming file %s to %s", file_hello, file_foo); + if (rename(file_hello, file_foo) != 0) + { + ESP_LOGE(TAG, "Rename failed"); + return; + } + + ret = s_example_read_file(file_foo); + if (ret != ESP_OK) + { + return; + } + + // Format FATFS + ret = esp_vfs_fat_sdcard_format(mount_point, card); + if (ret != ESP_OK) + { + ESP_LOGE(TAG, "Failed to format FATFS (%s)", esp_err_to_name(ret)); + return; + } + + if (stat(file_foo, &st) == 0) + { + ESP_LOGI(TAG, "file still exists"); + return; + } + else + { + ESP_LOGI(TAG, "file doesnt exist, format done"); + } + + const char *file_nihao = MOUNT_POINT "/nihao.txt"; + memset(data, 0, EXAMPLE_MAX_CHAR_SIZE); + snprintf(data, EXAMPLE_MAX_CHAR_SIZE, "%s %s!\n", "Nihao", card->cid.name); + ret = s_example_write_file(file_nihao, data); + if (ret != ESP_OK) + { + return; + } + + // Open file for reading + ret = s_example_read_file(file_nihao); + if (ret != ESP_OK) + { + return; + } + + // All done, unmount partition and disable SDMMC peripheral + esp_vfs_fat_sdcard_unmount(mount_point, card); + ESP_LOGI(TAG, "Card unmounted"); +} diff --git a/code/05.freertos_advanced/event_group/事件组同步/CMakeLists.txt b/code/05.freertos_advanced/event_group/事件组同步/CMakeLists.txt new file mode 100644 index 0000000..664d458 --- /dev/null +++ b/code/05.freertos_advanced/event_group/事件组同步/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(main) diff --git a/code/05.freertos_advanced/event_group/事件组同步/main/CMakeLists.txt b/code/05.freertos_advanced/event_group/事件组同步/main/CMakeLists.txt new file mode 100644 index 0000000..f3e5917 --- /dev/null +++ b/code/05.freertos_advanced/event_group/事件组同步/main/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") + +# target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format") diff --git a/code/05.freertos_advanced/event_group/事件组同步/main/main.c b/code/05.freertos_advanced/event_group/事件组同步/main/main.c new file mode 100644 index 0000000..3413e76 --- /dev/null +++ b/code/05.freertos_advanced/event_group/事件组同步/main/main.c @@ -0,0 +1,99 @@ +// 事件组 +#include +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/event_groups.h" + +/* Bits used by the three tasks. */ +#define TASK_0_BIT (1 << 0) +#define TASK_1_BIT (1 << 1) +#define TASK_2_BIT (1 << 2) + +#define ALL_SYNC_BITS (TASK_0_BIT | TASK_1_BIT | TASK_2_BIT) + +static const char *TAG = "main"; +EventGroupHandle_t xEventBits; + + +void task0(void *pvParameters) +{ + ESP_LOGI(TAG, "-------------------------------"); + ESP_LOGI(TAG, "task0启动!"); + + while (1) + { + vTaskDelay(pdMS_TO_TICKS(3000)); + ESP_LOGI(TAG, "task0: 任务同步开始"); + // 事件同步 + xEventGroupSync( + xEventBits, /* The event group being tested. */ + TASK_0_BIT, /* The bits within the event group to wait for. */ + ALL_SYNC_BITS, /* The bits within the event group to wait for. */ + portMAX_DELAY); /* Wait a maximum of 100ms for either bit to be set. */ + + ESP_LOGI(TAG, "task0: 任务同步完成"); + vTaskDelay(pdMS_TO_TICKS(3000)); + } +} +void task1(void *pvParameters) +{ + ESP_LOGI(TAG, "-------------------------------"); + ESP_LOGI(TAG, "task1启动!"); + + while (1) + { + vTaskDelay(pdMS_TO_TICKS(4000)); + ESP_LOGI(TAG, "task1: 任务同步开始"); + + // 事件同步 + xEventGroupSync( + xEventBits, /* The event group being tested. */ + TASK_1_BIT, /* The bits within the event group to wait for. */ + ALL_SYNC_BITS, /* The bits within the event group to wait for. */ + portMAX_DELAY); /* Wait a maximum of 100ms for either bit to be set. */ + + ESP_LOGI(TAG, "task1: 任务同步完成"); + vTaskDelay(pdMS_TO_TICKS(3000)); + } +} + +void task2(void *pvParameters) +{ + ESP_LOGI(TAG, "-------------------------------"); + ESP_LOGI(TAG, "task2启动!"); + + while (1) + { + vTaskDelay(pdMS_TO_TICKS(5000)); + ESP_LOGI(TAG, "task2: 任务同步开始"); + // 事件同步 + xEventGroupSync( + xEventBits, /* The event group being tested. */ + TASK_2_BIT, /* The bits within the event group to wait for. */ + ALL_SYNC_BITS, /* The bits within the event group to wait for. */ + portMAX_DELAY); /* Wait a maximum of 100ms for either bit to be set. */ + + ESP_LOGI(TAG, "task2: 任务同步完成"); + vTaskDelay(pdMS_TO_TICKS(3000)); + } +} + + +void app_main(void) +{ + + // 创建事件组 + xEventBits = xEventGroupCreate(); + + if (xEventBits == NULL) + { + ESP_LOGE(TAG, "创建事件组失败"); + } + else + { + xTaskCreate(task0, "task0", 1024 * 2, NULL, 1, NULL); + xTaskCreate(task1, "task1", 1024 * 2, NULL, 1, NULL); + xTaskCreate(task2, "task2", 1024 * 2, NULL, 1, NULL); + } +} diff --git a/code/05.freertos_advanced/event_group/事件组同步/sdkconfig.defaults b/code/05.freertos_advanced/event_group/事件组同步/sdkconfig.defaults new file mode 100644 index 0000000..cb398a7 --- /dev/null +++ b/code/05.freertos_advanced/event_group/事件组同步/sdkconfig.defaults @@ -0,0 +1,7 @@ +# This file was generated using idf.py save-defconfig. It can be edited manually. +# Espressif IoT Development Framework (ESP-IDF) 5.3.2 Project Minimal Configuration +# +CONFIG_IDF_TARGET="esp32s3" +CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y +CONFIG_FREERTOS_USE_TRACE_FACILITY=y +CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS=y diff --git a/code/05.freertos_advanced/event_group/事件组等待/CMakeLists.txt b/code/05.freertos_advanced/event_group/事件组等待/CMakeLists.txt new file mode 100644 index 0000000..664d458 --- /dev/null +++ b/code/05.freertos_advanced/event_group/事件组等待/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(main) diff --git a/code/05.freertos_advanced/event_group/事件组等待/main/CMakeLists.txt b/code/05.freertos_advanced/event_group/事件组等待/main/CMakeLists.txt new file mode 100644 index 0000000..f3e5917 --- /dev/null +++ b/code/05.freertos_advanced/event_group/事件组等待/main/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") + +# target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format") diff --git a/code/05.freertos_advanced/event_group/事件组等待/main/main.c b/code/05.freertos_advanced/event_group/事件组等待/main/main.c new file mode 100644 index 0000000..ba42b06 --- /dev/null +++ b/code/05.freertos_advanced/event_group/事件组等待/main/main.c @@ -0,0 +1,71 @@ +// 事件组 +#include +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/event_groups.h" + +static const char *TAG = "main"; + +EventGroupHandle_t xCreatedEventGroup; + +#define BIT_0 (1 << 0) +#define BIT_4 (1 << 4) + +void task1(void *pvParameters) +{ + ESP_LOGI(TAG, "-------------------------------"); + ESP_LOGI(TAG, "task1启动!"); + + while (1) + { + EventBits_t uxBits; + uxBits = xEventGroupWaitBits( + xCreatedEventGroup, /* The event group being tested. */ + BIT_0 | BIT_4, /* The bits within the event group to wait for. */ + pdTRUE, /* BIT_0 & BIT_4 should be cleared before returning. */ + pdFALSE, /* Don't wait for both bits, either bit will do. */ + portMAX_DELAY); /* Wait a maximum of 100ms for either bit to be set. */ + + if ((uxBits & (BIT_0 | BIT_4)) == (BIT_0 | BIT_4)) + { + ESP_LOGI(TAG, "BIT_0 和 BIT_4 都被设置了"); + } + else + { + ESP_LOGI(TAG, "BIT_0 和 BIT_4 有一个被设置了"); + } + } +} + +void task2(void *pvParameters) +{ + ESP_LOGI(TAG, "task2启动!"); + vTaskDelay(pdMS_TO_TICKS(1000)); + while (1) + { + xEventGroupSetBits(xCreatedEventGroup, BIT_0); + ESP_LOGI(TAG, "BIT_0 被设置"); + vTaskDelay(pdMS_TO_TICKS(3000)); + xEventGroupSetBits(xCreatedEventGroup, BIT_4); + ESP_LOGI(TAG, "BIT_4 被设置"); + vTaskDelay(pdMS_TO_TICKS(3000)); + } +} + +void app_main(void) +{ + + // 创建事件组 + xCreatedEventGroup = xEventGroupCreate(); + + if (xCreatedEventGroup == NULL) + { + ESP_LOGE(TAG, "创建事件组失败"); + } + else + { + xTaskCreate(task1, "task1", 1024 * 2, NULL, 1, NULL); + xTaskCreate(task2, "task2", 1024 * 2, NULL, 1, NULL); + } +} diff --git a/code/05.freertos_advanced/event_group/事件组等待/sdkconfig.defaults b/code/05.freertos_advanced/event_group/事件组等待/sdkconfig.defaults new file mode 100644 index 0000000..cb398a7 --- /dev/null +++ b/code/05.freertos_advanced/event_group/事件组等待/sdkconfig.defaults @@ -0,0 +1,7 @@ +# This file was generated using idf.py save-defconfig. It can be edited manually. +# Espressif IoT Development Framework (ESP-IDF) 5.3.2 Project Minimal Configuration +# +CONFIG_IDF_TARGET="esp32s3" +CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y +CONFIG_FREERTOS_USE_TRACE_FACILITY=y +CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS=y diff --git a/code/05.freertos_advanced/queue/队列传参_常量/CMakeLists.txt b/code/05.freertos_advanced/queue/队列传参_常量/CMakeLists.txt new file mode 100644 index 0000000..664d458 --- /dev/null +++ b/code/05.freertos_advanced/queue/队列传参_常量/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(main) diff --git a/code/05.freertos_advanced/queue/队列传参_常量/main/CMakeLists.txt b/code/05.freertos_advanced/queue/队列传参_常量/main/CMakeLists.txt new file mode 100644 index 0000000..f3e5917 --- /dev/null +++ b/code/05.freertos_advanced/queue/队列传参_常量/main/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") + +# target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format") diff --git a/code/05.freertos_advanced/queue/队列传参_常量/main/main.c b/code/05.freertos_advanced/queue/队列传参_常量/main/main.c new file mode 100644 index 0000000..5e9a3bc --- /dev/null +++ b/code/05.freertos_advanced/queue/队列传参_常量/main/main.c @@ -0,0 +1,78 @@ +#include +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" + +static const char *TAG = "main"; + +void Task_1(void *pvParameters) +{ + // 取得队列句柄 + QueueHandle_t xQueue = (QueueHandle_t)pvParameters; + int i = 0; + + for (;;) + { + // 发送数据到队列 + if (xQueueSend(xQueue, &i, 0)!= pdPASS) { + ESP_LOGI(TAG, "数据发送失败"); + } + else + { + ESP_LOGI(TAG, "数据发送成功"); + i++; + } + + if(i == 10) + { + i = 0; + } + vTaskDelay(1000 / portTICK_PERIOD_MS); + } + vTaskDelete(NULL); +} + +void Task_2(void *pvParameters) +{ + // 取得队列句柄 + QueueHandle_t xQueue = (QueueHandle_t)pvParameters; + for (;;) + { + int receivedData; + if (xQueueReceive(xQueue, &receivedData, 0) != pdPASS) + { + ESP_LOGI(TAG, "数据接收失败"); + } + else + { + ESP_LOGI(TAG, "数据接收成功,数据为:%d", receivedData); + } + vTaskDelay(1000 / portTICK_PERIOD_MS); + + } + vTaskDelete(NULL); +} + +void app_main(void) +{ + TaskHandle_t taskHandle_1 = NULL; + TaskHandle_t taskHandle_2 = NULL; + QueueHandle_t xQueue; + + // 创建队列 + xQueue = xQueueCreate(10, sizeof(int)); + + if (xQueue != NULL) + { + ESP_LOGI(TAG, "队列创建成功"); + // 发送数据任务 + xTaskCreate(Task_1, "Task_1", 1024 * 4, (void *)xQueue, 12, &taskHandle_1); + // 接收数据任务 + xTaskCreate(Task_2, "Task_1", 1024 * 4, (void *)xQueue, 12, &taskHandle_2); + } + else + { + ESP_LOGI(TAG, "队列创建失败"); + } +} diff --git a/code/05.freertos_advanced/queue/队列传参_常量/sdkconfig.defaults b/code/05.freertos_advanced/queue/队列传参_常量/sdkconfig.defaults new file mode 100644 index 0000000..cb398a7 --- /dev/null +++ b/code/05.freertos_advanced/queue/队列传参_常量/sdkconfig.defaults @@ -0,0 +1,7 @@ +# This file was generated using idf.py save-defconfig. It can be edited manually. +# Espressif IoT Development Framework (ESP-IDF) 5.3.2 Project Minimal Configuration +# +CONFIG_IDF_TARGET="esp32s3" +CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y +CONFIG_FREERTOS_USE_TRACE_FACILITY=y +CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS=y diff --git a/code/05.freertos_advanced/queue/队列传参_指针/CMakeLists.txt b/code/05.freertos_advanced/queue/队列传参_指针/CMakeLists.txt new file mode 100644 index 0000000..664d458 --- /dev/null +++ b/code/05.freertos_advanced/queue/队列传参_指针/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(main) diff --git a/code/05.freertos_advanced/queue/队列传参_指针/main/CMakeLists.txt b/code/05.freertos_advanced/queue/队列传参_指针/main/CMakeLists.txt new file mode 100644 index 0000000..f3e5917 --- /dev/null +++ b/code/05.freertos_advanced/queue/队列传参_指针/main/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") + +# target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format") diff --git a/code/05.freertos_advanced/queue/队列传参_指针/main/main.c b/code/05.freertos_advanced/queue/队列传参_指针/main/main.c new file mode 100644 index 0000000..c119f35 --- /dev/null +++ b/code/05.freertos_advanced/queue/队列传参_指针/main/main.c @@ -0,0 +1,85 @@ +// 队列传参_指针: 一般用于传递占用内存较大的数据. 传递指针, 可以避免拷贝数据, 提高效率. +#include +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" + +static const char *TAG = "main"; + +void Task_1(void *pvParameters) +{ + // 取得队列句柄 + QueueHandle_t xQueue = (QueueHandle_t)pvParameters; + int i = 0; + + for (;;) + { + char *pCharSend = (char *)malloc(50); // 申请内存 + snprintf(pCharSend, 50, "Hello World! - %d", i); + i++; + // 发送数据到队列 + if (xQueueSend(xQueue, &pCharSend, 0) != pdPASS) + { + ESP_LOGI(TAG, "数据发送失败"); + } + else + { + ESP_LOGI(TAG, "数据发送成功"); + + } + + if (i == 10) + { + i = 0; + } + vTaskDelay(1000 / portTICK_PERIOD_MS); + } + vTaskDelete(NULL); +} + +void Task_2(void *pvParameters) +{ + // 取得队列句柄 + QueueHandle_t xQueue = (QueueHandle_t)pvParameters; + + char *pCharReceived = NULL; // 接收数据 + for (;;) + { + if (xQueueReceive(xQueue, &pCharReceived, 0) != pdPASS) + { + ESP_LOGI(TAG, "数据接收失败"); + } + else + { + ESP_LOGI(TAG, "数据接收成功,数据为:%s", pCharReceived); + free(pCharReceived); // 释放内存 + } + vTaskDelay(1000 / portTICK_PERIOD_MS); + + } + vTaskDelete(NULL); +} + +void app_main(void) +{ + TaskHandle_t taskHandle_1 = NULL; + TaskHandle_t taskHandle_2 = NULL; + QueueHandle_t xQueue; + + // 创建队列 + xQueue = xQueueCreate(10, sizeof(char *)); + + if (xQueue != NULL) + { + ESP_LOGI(TAG, "队列创建成功"); + // 发送数据任务 + xTaskCreate(Task_1, "Task_1", 1024 * 4, (void *)xQueue, 12, &taskHandle_1); + // 接收数据任务 + xTaskCreate(Task_2, "Task_1", 1024 * 4, (void *)xQueue, 12, &taskHandle_2); + } + else + { + ESP_LOGI(TAG, "队列创建失败"); + } +} diff --git a/code/05.freertos_advanced/queue/队列传参_指针/sdkconfig.defaults b/code/05.freertos_advanced/queue/队列传参_指针/sdkconfig.defaults new file mode 100644 index 0000000..cb398a7 --- /dev/null +++ b/code/05.freertos_advanced/queue/队列传参_指针/sdkconfig.defaults @@ -0,0 +1,7 @@ +# This file was generated using idf.py save-defconfig. It can be edited manually. +# Espressif IoT Development Framework (ESP-IDF) 5.3.2 Project Minimal Configuration +# +CONFIG_IDF_TARGET="esp32s3" +CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y +CONFIG_FREERTOS_USE_TRACE_FACILITY=y +CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS=y diff --git a/code/05.freertos_advanced/queue/队列传参_结构体/CMakeLists.txt b/code/05.freertos_advanced/queue/队列传参_结构体/CMakeLists.txt new file mode 100644 index 0000000..664d458 --- /dev/null +++ b/code/05.freertos_advanced/queue/队列传参_结构体/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(main) diff --git a/code/05.freertos_advanced/queue/队列传参_结构体/main/CMakeLists.txt b/code/05.freertos_advanced/queue/队列传参_结构体/main/CMakeLists.txt new file mode 100644 index 0000000..f3e5917 --- /dev/null +++ b/code/05.freertos_advanced/queue/队列传参_结构体/main/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") + +# target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format") diff --git a/code/05.freertos_advanced/queue/队列传参_结构体/main/main.c b/code/05.freertos_advanced/queue/队列传参_结构体/main/main.c new file mode 100644 index 0000000..83aff7d --- /dev/null +++ b/code/05.freertos_advanced/queue/队列传参_结构体/main/main.c @@ -0,0 +1,86 @@ +#include +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" + +static const char *TAG = "main"; + +// 定义结构体 +typedef struct +{ + int id; + int data[3]; +} MyStruct; + +void Task_1(void *pvParameters) +{ + // 取得队列句柄 + QueueHandle_t xQueue = (QueueHandle_t)pvParameters; + MyStruct shendData = {1, {1, 2, 3}}; + + for (;;) + { + // 发送数据到队列 + if (xQueueSend(xQueue, &shendData, 0) != pdPASS) + { + ESP_LOGI(TAG, "数据发送失败"); + } + else + { + ESP_LOGI(TAG, "数据发送成功"); + shendData.id++; + } + + if (shendData.id == 10) + { + shendData.id = 0; + } + vTaskDelay(1000 / portTICK_PERIOD_MS); + } + vTaskDelete(NULL); +} + +void Task_2(void *pvParameters) +{ + // 取得队列句柄 + QueueHandle_t xQueue = (QueueHandle_t)pvParameters; + for (;;) + { + MyStruct receivedData; + if (xQueueReceive(xQueue, &receivedData, 0) != pdPASS) + { + ESP_LOGI(TAG, "数据接收失败"); + } + else + { + ESP_LOGI(TAG, "数据接收成功,数据为:%d-[%d,%d,%d]", receivedData.id, receivedData.data[0], receivedData.data[1], receivedData.data[2]); + } + vTaskDelay(1000 / portTICK_PERIOD_MS); + + } + vTaskDelete(NULL); +} + +void app_main(void) +{ + TaskHandle_t taskHandle_1 = NULL; + TaskHandle_t taskHandle_2 = NULL; + QueueHandle_t xQueue; + + // 创建队列 + xQueue = xQueueCreate(10, sizeof(MyStruct)); + + if (xQueue != NULL) + { + ESP_LOGI(TAG, "队列创建成功"); + // 发送数据任务 + xTaskCreate(Task_1, "Task_1", 1024 * 4, (void *)xQueue, 12, &taskHandle_1); + // 接收数据任务 + xTaskCreate(Task_2, "Task_1", 1024 * 4, (void *)xQueue, 12, &taskHandle_2); + } + else + { + ESP_LOGI(TAG, "队列创建失败"); + } +} diff --git a/code/05.freertos_advanced/queue/队列传参_结构体/sdkconfig.defaults b/code/05.freertos_advanced/queue/队列传参_结构体/sdkconfig.defaults new file mode 100644 index 0000000..cb398a7 --- /dev/null +++ b/code/05.freertos_advanced/queue/队列传参_结构体/sdkconfig.defaults @@ -0,0 +1,7 @@ +# This file was generated using idf.py save-defconfig. It can be edited manually. +# Espressif IoT Development Framework (ESP-IDF) 5.3.2 Project Minimal Configuration +# +CONFIG_IDF_TARGET="esp32s3" +CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y +CONFIG_FREERTOS_USE_TRACE_FACILITY=y +CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS=y diff --git a/code/05.freertos_advanced/queue/队列多进单出模型/CMakeLists.txt b/code/05.freertos_advanced/queue/队列多进单出模型/CMakeLists.txt new file mode 100644 index 0000000..664d458 --- /dev/null +++ b/code/05.freertos_advanced/queue/队列多进单出模型/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(main) diff --git a/code/05.freertos_advanced/queue/队列多进单出模型/main/CMakeLists.txt b/code/05.freertos_advanced/queue/队列多进单出模型/main/CMakeLists.txt new file mode 100644 index 0000000..f3e5917 --- /dev/null +++ b/code/05.freertos_advanced/queue/队列多进单出模型/main/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") + +# target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format") diff --git a/code/05.freertos_advanced/queue/队列多进单出模型/main/main.c b/code/05.freertos_advanced/queue/队列多进单出模型/main/main.c new file mode 100644 index 0000000..16205e7 --- /dev/null +++ b/code/05.freertos_advanced/queue/队列多进单出模型/main/main.c @@ -0,0 +1,97 @@ +// 队列多进单出: 任务1和任务2发送数据到队列,任务3接收数据 任务3的优先级高于任务1和任务2,已达到数据监听的目的 +// 参考:https://www.bilibili.com/video/BV1R44y177VS/?spm_id_from=333.788.top_right_bar_window_history.content.click&vd_source=ef5a0ab0106372751602034cdd9ab98e + +#include +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" + +static const char *TAG = "main"; + +void Task_1(void *pvParameters) +{ + // 取得队列句柄 + QueueHandle_t xQueue = (QueueHandle_t)pvParameters; + int i = 111; + + for (;;) + { + // 发送数据到队列 + if (xQueueSend(xQueue, &i, 0) != pdPASS) + { + ESP_LOGI(TAG, "任务1数据发送失败"); + } + else + { + ESP_LOGI(TAG, "任务1数据发送成功"); + } + vTaskDelay(1000 / portTICK_PERIOD_MS); + } + vTaskDelete(NULL); +} + +void Task_2(void *pvParameters) +{ + // 取得队列句柄 + QueueHandle_t xQueue = (QueueHandle_t)pvParameters; + int i = 222; + + for (;;) + { + // 发送数据到队列 + if (xQueueSend(xQueue, &i, 0) != pdPASS) + { + ESP_LOGI(TAG, "任务2数据发送失败"); + } + else + { + ESP_LOGI(TAG, "任务2数据发送成功"); + } + vTaskDelay(1000 / portTICK_PERIOD_MS); + } + vTaskDelete(NULL); +} + +void Task_3(void *pvParameters) +{ + // 取得队列句柄 + QueueHandle_t xQueue = (QueueHandle_t)pvParameters; + for (;;) + { + int receivedData; + // 使用portMAX_DELAY阻塞等待数据 + if (xQueueReceive(xQueue, &receivedData, portMAX_DELAY) != pdPASS) + { + ESP_LOGI(TAG, "任务3数据接收失败"); + } + else + { + ESP_LOGI(TAG, "任务3数据接收成功,数据为:%d", receivedData); + } + } + vTaskDelete(NULL); +} + +void app_main(void) +{ + + QueueHandle_t xQueue; + + // 创建队列 + xQueue = xQueueCreate(10, sizeof(int)); + + if (xQueue != NULL) + { + ESP_LOGI(TAG, "队列创建成功"); + // 发送数据任务 + xTaskCreate(Task_1, "Task_1", 1024 * 4, (void *)xQueue, 1, NULL); + xTaskCreate(Task_2, "Task_1", 1024 * 4, (void *)xQueue, 1, NULL); + // 接收数据任务 + xTaskCreate(Task_3, "Task_1", 1024 * 4, (void *)xQueue, 2, NULL); + } + else + { + ESP_LOGI(TAG, "队列创建失败"); + } +} diff --git a/code/05.freertos_advanced/queue/队列多进单出模型/sdkconfig.defaults b/code/05.freertos_advanced/queue/队列多进单出模型/sdkconfig.defaults new file mode 100644 index 0000000..cb398a7 --- /dev/null +++ b/code/05.freertos_advanced/queue/队列多进单出模型/sdkconfig.defaults @@ -0,0 +1,7 @@ +# This file was generated using idf.py save-defconfig. It can be edited manually. +# Espressif IoT Development Framework (ESP-IDF) 5.3.2 Project Minimal Configuration +# +CONFIG_IDF_TARGET="esp32s3" +CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y +CONFIG_FREERTOS_USE_TRACE_FACILITY=y +CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS=y diff --git a/code/05.freertos_advanced/queue/队列邮箱/CMakeLists.txt b/code/05.freertos_advanced/queue/队列邮箱/CMakeLists.txt new file mode 100644 index 0000000..664d458 --- /dev/null +++ b/code/05.freertos_advanced/queue/队列邮箱/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(main) diff --git a/code/05.freertos_advanced/queue/队列邮箱/main/CMakeLists.txt b/code/05.freertos_advanced/queue/队列邮箱/main/CMakeLists.txt new file mode 100644 index 0000000..f3e5917 --- /dev/null +++ b/code/05.freertos_advanced/queue/队列邮箱/main/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") + +# target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format") diff --git a/code/05.freertos_advanced/queue/队列邮箱/main/main.c b/code/05.freertos_advanced/queue/队列邮箱/main/main.c new file mode 100644 index 0000000..3a0cfdb --- /dev/null +++ b/code/05.freertos_advanced/queue/队列邮箱/main/main.c @@ -0,0 +1,127 @@ +// 队列邮箱: FreeRTOS的邮箱概念跟别的RTOS不一样,它是一个队列,队列长度只有1. +// 写邮箱:新数据覆盖旧数据,读邮箱:读数据时,数据不会被移除; +// 这意味着,第一次调用时会因为无数据而阻塞,一旦曾经写入数据,以后读邮箱时总能成功。 +// https : // www.bilibili.com/video/BV1zq4y1m7UK?spm_id_from=333.788.videopod.sections&vd_source=ef5a0ab0106372751602034cdd9ab98e + +#include +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" + +static const char *TAG = "main"; + +// 写数据队列 +void Task_1(void *pvParameters) +{ + // 取得队列句柄 + QueueHandle_t Mailbox = (QueueHandle_t)pvParameters; + int i = 0; + + for (;;) + { + // 发送数据到队列 + if (xQueueOverwrite(Mailbox, &i) != pdPASS) + { + ESP_LOGI(TAG, "任务1数据发送失败"); + } + else + { + ESP_LOGI(TAG, "任务1数据发送成功"); + } + i++; + vTaskDelay(1000 / portTICK_PERIOD_MS); + } + vTaskDelete(NULL); +} + + +// 读数据队列 +void Task_2(void *pvParameters) +{ + // 取得队列句柄 + QueueHandle_t Mailbox = (QueueHandle_t)pvParameters; + + int i = 0; + + for (;;) + { + // 读取数据 + if (xQueuePeek(Mailbox, &i, portMAX_DELAY) == pdPASS) + { + ESP_LOGI(TAG, "任务2数据读取成功,数据为:%d", i); + } + else + { + ESP_LOGI(TAG, "任务2数据读取失败"); + } + vTaskDelay(1000 / portTICK_PERIOD_MS); + } + vTaskDelete(NULL); +} + +void Task_3(void *pvParameters) +{ + // 取得队列句柄 + QueueHandle_t Mailbox = (QueueHandle_t)pvParameters; + int i = 0; + + for (;;) + { + // 读取数据 + if (xQueuePeek(Mailbox, &i, portMAX_DELAY) == pdPASS) + { + ESP_LOGI(TAG, "任务3数据读取成功,数据为:%d", i); + } + else + { + ESP_LOGI(TAG, "任务3数据读取失败"); + } + vTaskDelay(1000 / portTICK_PERIOD_MS); + } + vTaskDelete(NULL); +} + +void Task_4(void *pvParameters) +{ + // 取得队列句柄 + QueueHandle_t Mailbox = (QueueHandle_t)pvParameters; + int i = 0; + + for (;;) + { + // 读取数据 + if (xQueuePeek(Mailbox, &i, portMAX_DELAY) == pdPASS) + { + ESP_LOGI(TAG, "任务4数据读取成功,数据为:%d", i); + } + else + { + ESP_LOGI(TAG, "任务4数据读取失败"); + } + vTaskDelay(1000 / portTICK_PERIOD_MS); + } + vTaskDelete(NULL); +} + +void app_main(void) +{ + QueueHandle_t Mailbox; // 创建邮箱 + + // 创建队列(注意:队列长度只有1) + Mailbox = xQueueCreate(1, sizeof(int)); + + if ((Mailbox != NULL) ) + { + ESP_LOGI(TAG, "队列创建成功"); + // 写数据任务 + xTaskCreate(Task_1, "Task_1", 1024 * 4, (void *)Mailbox, 2, NULL); + xTaskCreate(Task_2, "Task_2", 1024 * 4, (void *)Mailbox, 1, NULL); + xTaskCreate(Task_3, "Task_3", 1024 * 4, (void *)Mailbox, 1, NULL); + xTaskCreate(Task_4, "Task_4", 1024 * 4, (void *)Mailbox, 1, NULL); + } + else + { + ESP_LOGI(TAG, "队列创建失败"); + } +} diff --git a/code/05.freertos_advanced/queue/队列邮箱/sdkconfig.defaults b/code/05.freertos_advanced/queue/队列邮箱/sdkconfig.defaults new file mode 100644 index 0000000..cb398a7 --- /dev/null +++ b/code/05.freertos_advanced/queue/队列邮箱/sdkconfig.defaults @@ -0,0 +1,7 @@ +# This file was generated using idf.py save-defconfig. It can be edited manually. +# Espressif IoT Development Framework (ESP-IDF) 5.3.2 Project Minimal Configuration +# +CONFIG_IDF_TARGET="esp32s3" +CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y +CONFIG_FREERTOS_USE_TRACE_FACILITY=y +CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS=y diff --git a/code/05.freertos_advanced/queue/队列集合/CMakeLists.txt b/code/05.freertos_advanced/queue/队列集合/CMakeLists.txt new file mode 100644 index 0000000..664d458 --- /dev/null +++ b/code/05.freertos_advanced/queue/队列集合/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(main) diff --git a/code/05.freertos_advanced/queue/队列集合/main/CMakeLists.txt b/code/05.freertos_advanced/queue/队列集合/main/CMakeLists.txt new file mode 100644 index 0000000..f3e5917 --- /dev/null +++ b/code/05.freertos_advanced/queue/队列集合/main/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") + +# target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format") diff --git a/code/05.freertos_advanced/queue/队列集合/main/main.c b/code/05.freertos_advanced/queue/队列集合/main/main.c new file mode 100644 index 0000000..71f4875 --- /dev/null +++ b/code/05.freertos_advanced/queue/队列集合/main/main.c @@ -0,0 +1,110 @@ +// 队列集合: +// https : // www.bilibili.com/video/BV1zq4y1m7UK?spm_id_from=333.788.videopod.sections&vd_source=ef5a0ab0106372751602034cdd9ab98e + +#include +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" + +static const char *TAG = "main"; + +void Task_1(void *pvParameters) +{ + // 取得队列句柄 + QueueHandle_t xQueue = (QueueHandle_t)pvParameters; + int i = 111; + + for (;;) + { + // 发送数据到队列 + if (xQueueSend(xQueue, &i, 0) != pdPASS) + { + ESP_LOGI(TAG, "任务1数据发送失败"); + } + else + { + ESP_LOGI(TAG, "任务1数据发送成功"); + } + vTaskDelay(1000 / portTICK_PERIOD_MS); + } + vTaskDelete(NULL); +} + +void Task_2(void *pvParameters) +{ + // 取得队列句柄 + QueueHandle_t xQueue = (QueueHandle_t)pvParameters; + int i = 222; + + for (;;) + { + // 发送数据到队列 + if (xQueueSend(xQueue, &i, 0) != pdPASS) + { + ESP_LOGI(TAG, "任务2数据发送失败"); + } + else + { + ESP_LOGI(TAG, "任务2数据发送成功"); + } + vTaskDelay(1000 / portTICK_PERIOD_MS); + } + vTaskDelete(NULL); +} + +void Task_3(void *pvParameters) +{ + // 取得队列集合句柄 + QueueSetHandle_t xQueueSet = (QueueSetHandle_t)pvParameters; + // 取得有数据队列句柄 + QueueSetMemberHandle_t QueueData; + for (;;) + { + QueueData = xQueueSelectFromSet(xQueueSet, portMAX_DELAY); + if (QueueData != NULL) + { + int i; + if (xQueueReceive(QueueData, &i, portMAX_DELAY) != pdPASS) + { + ESP_LOGI(TAG, "任务3数据接收失败"); + } + else + { + ESP_LOGI(TAG, "任务3数据接收成功,数据为:%d", i); + } + } + } + vTaskDelete(NULL); +} + +void app_main(void) +{ + QueueHandle_t xQueue_1; + QueueHandle_t xQueue_2; + // 创建队列 + xQueue_1 = xQueueCreate(10, sizeof(int)); + xQueue_2 = xQueueCreate(10, sizeof(int)); + + // 创建队列集合 + QueueSetHandle_t xQueueSet; + xQueueSet = xQueueCreateSet(20); + + // 将队列添加到队列集合 + xQueueAddToSet(xQueue_1, xQueueSet); + xQueueAddToSet(xQueue_2, xQueueSet); + + if ((xQueue_1 != NULL )&& (xQueue_2 != NULL) && (xQueueSet != NULL)) + { + ESP_LOGI(TAG, "队列创建成功"); + // 发送数据任务 + xTaskCreate(Task_1, "Task_1", 1024 * 4, (void *)xQueue_1, 1, NULL); + xTaskCreate(Task_2, "Task_1", 1024 * 4, (void *)xQueue_2, 1, NULL); + // 接收数据任务 + xTaskCreate(Task_3, "Task_1", 1024 * 4, (void *)xQueueSet, 2, NULL); + } + else + { + ESP_LOGI(TAG, "队列创建失败"); + } +} diff --git a/code/05.freertos_advanced/queue/队列集合/sdkconfig.defaults b/code/05.freertos_advanced/queue/队列集合/sdkconfig.defaults new file mode 100644 index 0000000..cb398a7 --- /dev/null +++ b/code/05.freertos_advanced/queue/队列集合/sdkconfig.defaults @@ -0,0 +1,7 @@ +# This file was generated using idf.py save-defconfig. It can be edited manually. +# Espressif IoT Development Framework (ESP-IDF) 5.3.2 Project Minimal Configuration +# +CONFIG_IDF_TARGET="esp32s3" +CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y +CONFIG_FREERTOS_USE_TRACE_FACILITY=y +CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS=y diff --git a/code/05.freertos_advanced/semphr/二进制信号量/CMakeLists.txt b/code/05.freertos_advanced/semphr/二进制信号量/CMakeLists.txt new file mode 100644 index 0000000..664d458 --- /dev/null +++ b/code/05.freertos_advanced/semphr/二进制信号量/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(main) diff --git a/code/05.freertos_advanced/semphr/二进制信号量/main/CMakeLists.txt b/code/05.freertos_advanced/semphr/二进制信号量/main/CMakeLists.txt new file mode 100644 index 0000000..f3e5917 --- /dev/null +++ b/code/05.freertos_advanced/semphr/二进制信号量/main/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") + +# target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format") diff --git a/code/05.freertos_advanced/semphr/二进制信号量/main/main.c b/code/05.freertos_advanced/semphr/二进制信号量/main/main.c new file mode 100644 index 0000000..f988ffd --- /dev/null +++ b/code/05.freertos_advanced/semphr/二进制信号量/main/main.c @@ -0,0 +1,60 @@ +// 二进制信号量 +#include +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" + +static const char *TAG = "main"; + +// 二进制信号量 +SemaphoreHandle_t semaphoreHandle; + +// 公共变量 +int shareVariable = 0; + +void task1(void *pvParameters) +{ + for (;;) + { + // 获取信号量,信号量变为0 + xSemaphoreTake(semaphoreHandle, portMAX_DELAY); + for (int i = 0; i < 10; i++) + { + shareVariable++; + ESP_LOGI(TAG, "task1 shareVariable:%d", shareVariable); + vTaskDelay(pdMS_TO_TICKS(1000)); + } + // 释放信号量,信号量变为1 + xSemaphoreGive(semaphoreHandle); + vTaskDelay(pdMS_TO_TICKS(1000)); + } +} + +void task2(void *pvParameters) +{ + for (;;) + { + // 获取信号量 + xSemaphoreTake(semaphoreHandle, portMAX_DELAY); + for (int i = 0; i < 10; i++) + { + shareVariable++; + ESP_LOGI(TAG, "task2 shareVariable:%d", shareVariable); + vTaskDelay(pdMS_TO_TICKS(1000)); + } + // 释放信号量,信号量变为1 + xSemaphoreGive(semaphoreHandle); + vTaskDelay(pdMS_TO_TICKS(1000)); + } +} + +void app_main(void) +{ + semaphoreHandle = xSemaphoreCreateBinary(); + xSemaphoreGive(semaphoreHandle); + + // 创建任务 + xTaskCreate(task1, "task1", 1024 * 2, NULL, 10, NULL); + xTaskCreate(task2, "task2", 1024 * 2, NULL, 10, NULL); +} diff --git a/code/05.freertos_advanced/semphr/二进制信号量/sdkconfig.defaults b/code/05.freertos_advanced/semphr/二进制信号量/sdkconfig.defaults new file mode 100644 index 0000000..cb398a7 --- /dev/null +++ b/code/05.freertos_advanced/semphr/二进制信号量/sdkconfig.defaults @@ -0,0 +1,7 @@ +# This file was generated using idf.py save-defconfig. It can be edited manually. +# Espressif IoT Development Framework (ESP-IDF) 5.3.2 Project Minimal Configuration +# +CONFIG_IDF_TARGET="esp32s3" +CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y +CONFIG_FREERTOS_USE_TRACE_FACILITY=y +CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS=y diff --git a/code/05.freertos_advanced/semphr/互斥量/CMakeLists.txt b/code/05.freertos_advanced/semphr/互斥量/CMakeLists.txt new file mode 100644 index 0000000..664d458 --- /dev/null +++ b/code/05.freertos_advanced/semphr/互斥量/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(main) diff --git a/code/05.freertos_advanced/semphr/互斥量/main/CMakeLists.txt b/code/05.freertos_advanced/semphr/互斥量/main/CMakeLists.txt new file mode 100644 index 0000000..f3e5917 --- /dev/null +++ b/code/05.freertos_advanced/semphr/互斥量/main/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") + +# target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format") diff --git a/code/05.freertos_advanced/semphr/互斥量/main/main.c b/code/05.freertos_advanced/semphr/互斥量/main/main.c new file mode 100644 index 0000000..9d27e6b --- /dev/null +++ b/code/05.freertos_advanced/semphr/互斥量/main/main.c @@ -0,0 +1,80 @@ +// 互斥量(互斥锁Mutex):互斥锁和二进制信号量极为相似,但 有一些细微差异:互斥锁具有优先级继承机制, 但二进制信号量没有。 +#include +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" + +static const char *TAG = "main"; + +SemaphoreHandle_t mutexHandle; + +void task1(void *pvParameters) +{ + ESP_LOGI(TAG, "task1启动!"); + while (1) + { + if (xSemaphoreTake(mutexHandle, portMAX_DELAY) == pdTRUE) + { + ESP_LOGI(TAG, "task1获取到互斥量!"); + for (int i = 0; i < 10; i++) + { + ESP_LOGI(TAG, "task1执行中...%d", i); + vTaskDelay(pdMS_TO_TICKS(1000)); + } + xSemaphoreGive(mutexHandle); + ESP_LOGI(TAG, "task1释放互斥量!"); + vTaskDelay(pdMS_TO_TICKS(1000)); + } + else + { + ESP_LOGI(TAG, "task1获取互斥量失败!"); + vTaskDelay(pdMS_TO_TICKS(1000)); + } + } +} + +void task2(void *pvParameters) +{ + ESP_LOGI(TAG, "task2启动!"); + vTaskDelay(pdMS_TO_TICKS(1000)); + while (1) + { + } +} + +void task3(void *pvParameters) +{ + ESP_LOGI(TAG, "task3启动!"); + vTaskDelay(pdMS_TO_TICKS(1000)); + while (1) + { + if (xSemaphoreTake(mutexHandle, 1000) == pdPASS) + { + ESP_LOGI(TAG, "task3获取到互斥量!"); + for (int i = 0; i < 10; i++) + { + ESP_LOGI(TAG, "task3执行中...%d",i); + vTaskDelay(pdMS_TO_TICKS(1000)); + } + + xSemaphoreGive(mutexHandle); + ESP_LOGI(TAG, "task3释放互斥量!"); + vTaskDelay(pdMS_TO_TICKS(5000)); + } + else + { + ESP_LOGI(TAG, "task3未获取到互斥量!"); + vTaskDelay(pdMS_TO_TICKS(1000)); + } + } +} + +void app_main(void) +{ + mutexHandle = xSemaphoreCreateMutex(); + // mutexHandle = xSemaphoreCreateBinary(); + xTaskCreate(task1, "task1", 1024 * 2, NULL, 1, NULL); + xTaskCreate(task2, "task2", 1024 * 2, NULL, 2, NULL); + xTaskCreate(task3, "task3", 1024 * 2, NULL, 3, NULL); +} diff --git a/code/05.freertos_advanced/semphr/互斥量/sdkconfig.defaults b/code/05.freertos_advanced/semphr/互斥量/sdkconfig.defaults new file mode 100644 index 0000000..cb398a7 --- /dev/null +++ b/code/05.freertos_advanced/semphr/互斥量/sdkconfig.defaults @@ -0,0 +1,7 @@ +# This file was generated using idf.py save-defconfig. It can be edited manually. +# Espressif IoT Development Framework (ESP-IDF) 5.3.2 Project Minimal Configuration +# +CONFIG_IDF_TARGET="esp32s3" +CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y +CONFIG_FREERTOS_USE_TRACE_FACILITY=y +CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS=y diff --git a/code/05.freertos_advanced/semphr/计数信号量/CMakeLists.txt b/code/05.freertos_advanced/semphr/计数信号量/CMakeLists.txt new file mode 100644 index 0000000..664d458 --- /dev/null +++ b/code/05.freertos_advanced/semphr/计数信号量/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(main) diff --git a/code/05.freertos_advanced/semphr/计数信号量/main/CMakeLists.txt b/code/05.freertos_advanced/semphr/计数信号量/main/CMakeLists.txt new file mode 100644 index 0000000..f3e5917 --- /dev/null +++ b/code/05.freertos_advanced/semphr/计数信号量/main/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") + +# target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format") diff --git a/code/05.freertos_advanced/semphr/计数信号量/main/main.c b/code/05.freertos_advanced/semphr/计数信号量/main/main.c new file mode 100644 index 0000000..18dd04c --- /dev/null +++ b/code/05.freertos_advanced/semphr/计数信号量/main/main.c @@ -0,0 +1,59 @@ +// 计数型信号量(占座) +#include +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" + +static const char *TAG = "main"; + +// 信号量 +SemaphoreHandle_t semaphoreHandle; + + +// 占座任务 +void task1(void *pvParameters) +{ + // 定义空位 + int seat = 0; + for (;;) + { + // 获取信号量 + seat = uxSemaphoreGetCount(semaphoreHandle); + // 输出空位 + ESP_LOGI(TAG, "当前空位:%d", seat); + + // 获取信号量(占座) + if (xSemaphoreTake(semaphoreHandle, portMAX_DELAY) == pdPASS) + { + ESP_LOGI(TAG, "占座成功"); + } + else + { + ESP_LOGI(TAG, "占座失败"); + } + vTaskDelay(pdMS_TO_TICKS(1000)); + } +} + +// 离开座位任务 +void task2(void *pvParameters) +{ + for (;;) + { + vTaskDelay(pdMS_TO_TICKS(6000)); + // 释放信号量 + xSemaphoreGive(semaphoreHandle); + ESP_LOGI(TAG, "释放座位"); + } +} + +void app_main(void) +{ + semaphoreHandle = xSemaphoreCreateCounting(5, 5); + + // 创建占座任务 + xTaskCreate(task1, "task1", 1024 * 2, NULL, 10, NULL); + // 创建离开座位任务 + xTaskCreate(task2, "task2", 1024 * 2, NULL, 10, NULL); +} diff --git a/code/05.freertos_advanced/semphr/计数信号量/sdkconfig.defaults b/code/05.freertos_advanced/semphr/计数信号量/sdkconfig.defaults new file mode 100644 index 0000000..cb398a7 --- /dev/null +++ b/code/05.freertos_advanced/semphr/计数信号量/sdkconfig.defaults @@ -0,0 +1,7 @@ +# This file was generated using idf.py save-defconfig. It can be edited manually. +# Espressif IoT Development Framework (ESP-IDF) 5.3.2 Project Minimal Configuration +# +CONFIG_IDF_TARGET="esp32s3" +CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y +CONFIG_FREERTOS_USE_TRACE_FACILITY=y +CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS=y diff --git a/code/05.freertos_advanced/semphr/递归互斥量/CMakeLists.txt b/code/05.freertos_advanced/semphr/递归互斥量/CMakeLists.txt new file mode 100644 index 0000000..664d458 --- /dev/null +++ b/code/05.freertos_advanced/semphr/递归互斥量/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(main) diff --git a/code/05.freertos_advanced/semphr/递归互斥量/main/CMakeLists.txt b/code/05.freertos_advanced/semphr/递归互斥量/main/CMakeLists.txt new file mode 100644 index 0000000..f3e5917 --- /dev/null +++ b/code/05.freertos_advanced/semphr/递归互斥量/main/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") + +# target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format") diff --git a/code/05.freertos_advanced/semphr/递归互斥量/main/main.c b/code/05.freertos_advanced/semphr/递归互斥量/main/main.c new file mode 100644 index 0000000..3f2c795 --- /dev/null +++ b/code/05.freertos_advanced/semphr/递归互斥量/main/main.c @@ -0,0 +1,79 @@ +// 递归互斥量 +// 非递归互斥锁只能被一个任务 获取一次,如果同一个任务想再次获取则会失败, 因为当任务第一次释放互斥锁时,互斥锁就一直处于释放状态。 +// 与非递归互斥锁相反,递归互斥锁可以被同一个任务获取很多次, 获取多少次就需要释放多少次, 此时才会返回递归互斥锁。 +#include +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" + +static const char *TAG = "main"; + +SemaphoreHandle_t mutexHandle; + +void task1(void *pvParameters) +{ + ESP_LOGI(TAG, "-------------------------------"); + ESP_LOGI(TAG, "task1启动!"); + while (1) + { + xSemaphoreTakeRecursive(mutexHandle, portMAX_DELAY); + ESP_LOGI(TAG, "task1获取到互斥量-使用资源A"); + for (int i = 0; i < 10; i++) + { + ESP_LOGI(TAG, "task1执行中...%d -使用资源A", i); + vTaskDelay(pdMS_TO_TICKS(1000)); + } + + xSemaphoreTakeRecursive(mutexHandle, portMAX_DELAY); + ESP_LOGI(TAG, "task1获取到互斥量-使用资源B"); + for (int i = 0; i < 10; i++) + { + ESP_LOGI(TAG, "task1执行中...%d -使用资源B", i); + vTaskDelay(pdMS_TO_TICKS(1000)); + } + + xSemaphoreGiveRecursive(mutexHandle); + ESP_LOGI(TAG, "task1释放互斥量-使用资源B"); + vTaskDelay(pdMS_TO_TICKS(3000)); + xSemaphoreGiveRecursive(mutexHandle); + ESP_LOGI(TAG, "task1释放互斥量-使用资源A"); + } + vTaskDelete(NULL); +} + +void task2(void *pvParameters) +{ + ESP_LOGI(TAG, "task2启动!"); + vTaskDelay(pdMS_TO_TICKS(1000)); + while (1) + { + // 获取递归互斥锁 + if (xSemaphoreTakeRecursive(mutexHandle, portMAX_DELAY) == pdTRUE) + { + ESP_LOGI(TAG, "task2获取到互斥量"); + for (int i = 0; i < 10; i++) + + { + ESP_LOGI(TAG, "task2执行中...%d", i); + vTaskDelay(pdMS_TO_TICKS(1000)); + } + xSemaphoreGiveRecursive(mutexHandle); + ESP_LOGI(TAG, "task2释放互斥量"); + } + else + { + ESP_LOGI(TAG, "task2获取互斥量失败"); + vTaskDelay(pdMS_TO_TICKS(1000)); + } + } +} + +void app_main(void) +{ + // 创建递归互斥量 + mutexHandle = xSemaphoreCreateRecursiveMutex(); + + xTaskCreate(task1, "task1", 1024 * 2, NULL, 1, NULL); + xTaskCreate(task2, "task2", 1024 * 2, NULL, 2, NULL); +} diff --git a/code/05.freertos_advanced/semphr/递归互斥量/sdkconfig.defaults b/code/05.freertos_advanced/semphr/递归互斥量/sdkconfig.defaults new file mode 100644 index 0000000..cb398a7 --- /dev/null +++ b/code/05.freertos_advanced/semphr/递归互斥量/sdkconfig.defaults @@ -0,0 +1,7 @@ +# This file was generated using idf.py save-defconfig. It can be edited manually. +# Espressif IoT Development Framework (ESP-IDF) 5.3.2 Project Minimal Configuration +# +CONFIG_IDF_TARGET="esp32s3" +CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y +CONFIG_FREERTOS_USE_TRACE_FACILITY=y +CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS=y diff --git a/code/05.freertos_advanced/task_notify/任务通知值/CMakeLists.txt b/code/05.freertos_advanced/task_notify/任务通知值/CMakeLists.txt new file mode 100644 index 0000000..664d458 --- /dev/null +++ b/code/05.freertos_advanced/task_notify/任务通知值/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(main) diff --git a/code/05.freertos_advanced/task_notify/任务通知值/main/CMakeLists.txt b/code/05.freertos_advanced/task_notify/任务通知值/main/CMakeLists.txt new file mode 100644 index 0000000..f3e5917 --- /dev/null +++ b/code/05.freertos_advanced/task_notify/任务通知值/main/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") + +# target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format") diff --git a/code/05.freertos_advanced/task_notify/任务通知值/main/main.c b/code/05.freertos_advanced/task_notify/任务通知值/main/main.c new file mode 100644 index 0000000..4356665 --- /dev/null +++ b/code/05.freertos_advanced/task_notify/任务通知值/main/main.c @@ -0,0 +1,65 @@ +// 任务通知值按位判断-代替队列邮箱或者事件组 +#include +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +static const char *TAG = "main"; + +static TaskHandle_t xTask1 = NULL, xTask2 = NULL; + +void task1(void *pvParameters) +{ + ESP_LOGI(TAG, "-------------------------------"); + ESP_LOGI(TAG, "task1启动!"); + + uint32_t ulNotifiedValue; + + while (1) + { + ESP_LOGI(TAG, "task1: 等待task通知"); + xTaskNotifyWait(0x00, ULONG_MAX, &ulNotifiedValue, portMAX_DELAY); + // 通过不同的bit位来判断通知的来源 + if ((ulNotifiedValue & 0x01) != 0) + { + ESP_LOGI(TAG, "task1: 收到task通知-bit0"); + } + if ((ulNotifiedValue & 0x02) != 0) + { + ESP_LOGI(TAG, "task1: 收到task通知-bit1"); + } + if ((ulNotifiedValue & 0x04) != 0) + { + ESP_LOGI(TAG, "task1: 收到task通知-bit2"); + } + } +} + +void task2(void *pvParameters) +{ + ESP_LOGI(TAG, "-------------------------------"); + ESP_LOGI(TAG, "task2启动!"); + + while (1) + { + vTaskDelay(pdMS_TO_TICKS(5000)); + ESP_LOGI(TAG, "task2: 发送task通知-bit0"); + xTaskNotify(xTask1, 0x01, eSetValueWithOverwrite); + + vTaskDelay(pdMS_TO_TICKS(5000)); + ESP_LOGI(TAG, "task2: 发送task通知-bit1"); + xTaskNotify(xTask1, 0x02, eSetValueWithOverwrite); + + vTaskDelay(pdMS_TO_TICKS(5000)); + ESP_LOGI(TAG, "task2: 发送task通知-bit2"); + xTaskNotify(xTask1, 0x04, eSetValueWithOverwrite); + + } +} + +void app_main(void) +{ + + xTaskCreate(task1, "task1", 1024 * 4, NULL, 1, &xTask1); + xTaskCreate(task2, "task2", 1024 * 4, NULL, 1, &xTask2); +} diff --git a/code/05.freertos_advanced/task_notify/任务通知值/sdkconfig.defaults b/code/05.freertos_advanced/task_notify/任务通知值/sdkconfig.defaults new file mode 100644 index 0000000..cb398a7 --- /dev/null +++ b/code/05.freertos_advanced/task_notify/任务通知值/sdkconfig.defaults @@ -0,0 +1,7 @@ +# This file was generated using idf.py save-defconfig. It can be edited manually. +# Espressif IoT Development Framework (ESP-IDF) 5.3.2 Project Minimal Configuration +# +CONFIG_IDF_TARGET="esp32s3" +CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y +CONFIG_FREERTOS_USE_TRACE_FACILITY=y +CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS=y diff --git a/code/05.freertos_advanced/task_notify/直接任务通知/CMakeLists.txt b/code/05.freertos_advanced/task_notify/直接任务通知/CMakeLists.txt new file mode 100644 index 0000000..664d458 --- /dev/null +++ b/code/05.freertos_advanced/task_notify/直接任务通知/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(main) diff --git a/code/05.freertos_advanced/task_notify/直接任务通知/main/CMakeLists.txt b/code/05.freertos_advanced/task_notify/直接任务通知/main/CMakeLists.txt new file mode 100644 index 0000000..f3e5917 --- /dev/null +++ b/code/05.freertos_advanced/task_notify/直接任务通知/main/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") + +# target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format") diff --git a/code/05.freertos_advanced/task_notify/直接任务通知/main/main.c b/code/05.freertos_advanced/task_notify/直接任务通知/main/main.c new file mode 100644 index 0000000..91e8c78 --- /dev/null +++ b/code/05.freertos_advanced/task_notify/直接任务通知/main/main.c @@ -0,0 +1,44 @@ +// 事件组 +#include +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +static const char *TAG = "main"; + +static TaskHandle_t xTask1 = NULL, xTask2 = NULL; + +void task1(void *pvParameters) +{ + ESP_LOGI(TAG, "-------------------------------"); + ESP_LOGI(TAG, "task1启动!"); + + while (1) + { + ESP_LOGI(TAG, "task1: 等待task通知"); + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + + ESP_LOGI(TAG, "task1: 收到task通知"); + vTaskDelay(pdMS_TO_TICKS(3000)); + } +} + +void task2(void *pvParameters) +{ + ESP_LOGI(TAG, "-------------------------------"); + ESP_LOGI(TAG, "task2启动!"); + + while (1) + { + vTaskDelay(pdMS_TO_TICKS(5000)); + ESP_LOGI(TAG, "task2: 发送task通知"); + xTaskNotifyGive(xTask1); + } +} + +void app_main(void) +{ + + xTaskCreate(task1, "task1", 1024 * 2, NULL, 1, &xTask1); + xTaskCreate(task2, "task2", 1024 * 2, NULL, 1, &xTask2); +} diff --git a/code/05.freertos_advanced/task_notify/直接任务通知/sdkconfig.defaults b/code/05.freertos_advanced/task_notify/直接任务通知/sdkconfig.defaults new file mode 100644 index 0000000..cb398a7 --- /dev/null +++ b/code/05.freertos_advanced/task_notify/直接任务通知/sdkconfig.defaults @@ -0,0 +1,7 @@ +# This file was generated using idf.py save-defconfig. It can be edited manually. +# Espressif IoT Development Framework (ESP-IDF) 5.3.2 Project Minimal Configuration +# +CONFIG_IDF_TARGET="esp32s3" +CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y +CONFIG_FREERTOS_USE_TRACE_FACILITY=y +CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS=y diff --git a/code/05.wifi/espnow/recv/.gitignore b/code/05.wifi/espnow/recv/.gitignore new file mode 100644 index 0000000..8da877b --- /dev/null +++ b/code/05.wifi/espnow/recv/.gitignore @@ -0,0 +1,6 @@ +build +*managed_components +dependencies.lock +sdkconfig +sdkconfig.old + diff --git a/code/05.wifi/espnow/recv/CMakeLists.txt b/code/05.wifi/espnow/recv/CMakeLists.txt new file mode 100644 index 0000000..664d458 --- /dev/null +++ b/code/05.wifi/espnow/recv/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(main) diff --git a/code/05.wifi/espnow/recv/main/CMakeLists.txt b/code/05.wifi/espnow/recv/main/CMakeLists.txt new file mode 100644 index 0000000..cf2c455 --- /dev/null +++ b/code/05.wifi/espnow/recv/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") diff --git a/code/05.wifi/espnow/recv/main/main.c b/code/05.wifi/espnow/recv/main/main.c new file mode 100644 index 0000000..8573046 --- /dev/null +++ b/code/05.wifi/espnow/recv/main/main.c @@ -0,0 +1,83 @@ +#include +#include +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" +#include "freertos/timers.h" +#include "nvs_flash.h" +#include "esp_random.h" +#include "esp_event.h" +#include "esp_netif.h" +#include "esp_wifi.h" +#include "esp_log.h" +#include "esp_mac.h" +#include "esp_now.h" +#include "esp_crc.h" + +// 接收方地址 +// static uint8_t s_broadcast_mac[ESP_NOW_ETH_ALEN] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; +static uint8_t s_broadcast_mac[ESP_NOW_ETH_ALEN] = {0x24, 0xdc, 0xc3, 0x9c, 0xeb, 0x18}; + +static const char *TAG = "espnow"; + +/* WiFi should start before using ESPNOW */ +static void wifi_init(void) +{ + ESP_ERROR_CHECK(esp_netif_init()); + ESP_ERROR_CHECK(esp_event_loop_create_default()); + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM)); + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); + ESP_ERROR_CHECK(esp_wifi_start()); +} + +// ESPNOW接收回调函数 +static void example_espnow_recv_cb(const esp_now_recv_info_t *recv_info, const uint8_t *data, int len) +{ + ESP_LOGI(TAG, "Receive data from: " MACSTR ", len: %d", MAC2STR(recv_info->src_addr), len); + ESP_LOGI(TAG, "Data: %s", data); +} + +// ESPNOW接受数据任务 +static void espnow_task(void *pvParameter) +{ + ESP_LOGI(TAG, "Start receiving data"); + while (1) + { + vTaskDelay(1000 / portTICK_PERIOD_MS); + } +} + +static esp_err_t espnow_init(void) +{ + + /* Initialize ESPNOW and register sending and receiving callback function. */ + ESP_ERROR_CHECK(esp_now_init()); + // 注册接受回调函数 + //ESP_ERROR_CHECK(esp_now_register_send_cb(example_espnow_send_cb)); + ESP_ERROR_CHECK(esp_now_register_recv_cb(example_espnow_recv_cb)); + + xTaskCreate(espnow_task, "espnow_task", 2048, NULL, 4, NULL); + + return ESP_OK; +} + +void app_main(void) +{ + // Initialize NVS + esp_err_t ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) + { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK(ret); + + // Initialize WiFi + wifi_init(); + + // Initialize ESPNOW + espnow_init(); +} diff --git a/code/05.wifi/espnow/send/.gitignore b/code/05.wifi/espnow/send/.gitignore new file mode 100644 index 0000000..8da877b --- /dev/null +++ b/code/05.wifi/espnow/send/.gitignore @@ -0,0 +1,6 @@ +build +*managed_components +dependencies.lock +sdkconfig +sdkconfig.old + diff --git a/code/05.wifi/espnow/send/CMakeLists.txt b/code/05.wifi/espnow/send/CMakeLists.txt new file mode 100644 index 0000000..664d458 --- /dev/null +++ b/code/05.wifi/espnow/send/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(main) diff --git a/code/05.wifi/espnow/send/main/CMakeLists.txt b/code/05.wifi/espnow/send/main/CMakeLists.txt new file mode 100644 index 0000000..cf2c455 --- /dev/null +++ b/code/05.wifi/espnow/send/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") diff --git a/code/05.wifi/espnow/send/main/main.c b/code/05.wifi/espnow/send/main/main.c new file mode 100644 index 0000000..d12bae1 --- /dev/null +++ b/code/05.wifi/espnow/send/main/main.c @@ -0,0 +1,113 @@ +#include +#include +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" +#include "freertos/timers.h" +#include "nvs_flash.h" +#include "esp_random.h" +#include "esp_event.h" +#include "esp_netif.h" +#include "esp_wifi.h" +#include "esp_log.h" +#include "esp_mac.h" +#include "esp_now.h" +#include "esp_crc.h" + +// 接收方地址 +//static uint8_t s_broadcast_mac[ESP_NOW_ETH_ALEN] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; +static uint8_t s_broadcast_mac[ESP_NOW_ETH_ALEN] = {0x24, 0xdc, 0xc3, 0x9c, 0xeb, 0x18}; + +static const char *TAG = "espnow"; + +/* WiFi should start before using ESPNOW */ +static void wifi_init(void) +{ + ESP_ERROR_CHECK(esp_netif_init()); + ESP_ERROR_CHECK(esp_event_loop_create_default()); + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM)); + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); + ESP_ERROR_CHECK(esp_wifi_start()); + +} + +static void example_espnow_send_cb(const uint8_t *mac_addr, esp_now_send_status_t status) +{ + if (status != ESP_NOW_SEND_SUCCESS) + { + ESP_LOGE(TAG, "Send error"); + } + else + { + ESP_LOGI(TAG, "Send success"); + } +} + +// ESPNOW发送任务 +static void espnow_task(void *pvParameter) +{ + char send_msg[] = "ESPNOW test!"; + ESP_LOGI(TAG, "Start sending broadcast data"); + while (1) + { + // 发送数据 + if (esp_now_send(s_broadcast_mac, (uint8_t *)send_msg, sizeof(send_msg)) != ESP_OK) + { + ESP_LOGE(TAG, "Send error"); + } + vTaskDelay(1000 / portTICK_PERIOD_MS); + } +} + +static esp_err_t espnow_init(void) +{ + + /* Initialize ESPNOW and register sending and receiving callback function. */ + ESP_ERROR_CHECK(esp_now_init()); + // 注册发送回调函数 + ESP_ERROR_CHECK(esp_now_register_send_cb(example_espnow_send_cb)); + //ESP_ERROR_CHECK(esp_now_register_recv_cb(example_espnow_recv_cb)); + + // 将广播对等方信息添加到对等方列表 + esp_now_peer_info_t *peer = malloc(sizeof(esp_now_peer_info_t)); + if (peer == NULL) + { + ESP_LOGE(TAG, "Malloc peer information fail"); + esp_now_deinit(); + return ESP_FAIL; + } + // 初始化对等方信息 + memset(peer, 0, sizeof(esp_now_peer_info_t)); + peer->channel = 1; + peer->ifidx = ESP_IF_WIFI_STA; + peer->encrypt = false; + memcpy(peer->peer_addr, s_broadcast_mac, ESP_NOW_ETH_ALEN); + // 添加对等方 + ESP_ERROR_CHECK(esp_now_add_peer(peer)); + free(peer); + + xTaskCreate(espnow_task, "espnow_task", 2048, NULL, 4, NULL); + + return ESP_OK; +} + +void app_main(void) +{ + // Initialize NVS + esp_err_t ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) + { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK(ret); + + // Initialize WiFi + wifi_init(); + + // Initialize ESPNOW + espnow_init(); +} diff --git a/code/05.wifi/http/http_client/.gitignore b/code/05.wifi/http/http_client/.gitignore new file mode 100644 index 0000000..8da877b --- /dev/null +++ b/code/05.wifi/http/http_client/.gitignore @@ -0,0 +1,6 @@ +build +*managed_components +dependencies.lock +sdkconfig +sdkconfig.old + diff --git a/code/05.wifi/http/http_client/CMakeLists.txt b/code/05.wifi/http/http_client/CMakeLists.txt new file mode 100644 index 0000000..664d458 --- /dev/null +++ b/code/05.wifi/http/http_client/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(main) diff --git a/code/05.wifi/http/http_client/main/CMakeLists.txt b/code/05.wifi/http/http_client/main/CMakeLists.txt new file mode 100644 index 0000000..cf2c455 --- /dev/null +++ b/code/05.wifi/http/http_client/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") diff --git a/code/05.wifi/http/http_client/main/main.c b/code/05.wifi/http/http_client/main/main.c new file mode 100644 index 0000000..ce7ecee --- /dev/null +++ b/code/05.wifi/http/http_client/main/main.c @@ -0,0 +1,200 @@ +#include +#include +#include +#include +#include "esp_log.h" +#include "nvs_flash.h" +#include "esp_event.h" +#include "esp_netif.h" +#include "esp_tls.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_system.h" +#include "esp_wifi.h" +#include "esp_mac.h" +#include +#include "esp_http_client.h" + +// 要连接的WIFI +#define ESP_WIFI_STA_SSID "duruofu_win10" +#define ESP_WIFI_STA_PASSWD "1234567890" +static const char *TAG = "main"; + +// 最大http输出缓冲区 +#define MAX_HTTP_OUTPUT_BUFFER 2048 + +// WIFI事件回调 +void WIFI_CallBack(void *event_handler_arg, esp_event_base_t event_base, int32_t event_id, void *event_data) +{ + static uint8_t connect_count = 0; + // WIFI 启动成功 + if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) + { + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_START"); + ESP_ERROR_CHECK(esp_wifi_connect()); + } + // WIFI 连接失败 + if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) + { + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_DISCONNECTED"); + connect_count++; + if (connect_count < 6) + { + vTaskDelay(1000 / portTICK_PERIOD_MS); + ESP_ERROR_CHECK(esp_wifi_connect()); + } + else + { + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_DISCONNECTED 10 times"); + } + } + // WIFI 连接成功(获取到了IP) + if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) + { + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_GOT_IP"); + ip_event_got_ip_t *info = (ip_event_got_ip_t *)event_data; + ESP_LOGI("WIFI_EVENT", "got ip:" IPSTR "", IP2STR(&info->ip_info.ip)); + } +} + +// 连接WIFI +static void wifi_sta_init(void) +{ + ESP_ERROR_CHECK(esp_netif_init()); + + // 注册事件(wifi启动成功) + ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, WIFI_EVENT_STA_START, WIFI_CallBack, NULL, NULL)); + // 注册事件(wifi连接失败) + ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, WIFI_CallBack, NULL, NULL)); + // 注册事件(wifi连接失败) + ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, WIFI_CallBack, NULL, NULL)); + + // 初始化STA设备 + esp_netif_create_default_wifi_sta(); + + /*Initialize WiFi */ + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + // WIFI_INIT_CONFIG_DEFAULT 是一个默认配置的宏 + + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + + //----------------配置阶段------------------- + // 初始化WIFI设备( 为 WiFi 驱动初始化 WiFi 分配资源,如 WiFi 控制结构、RX/TX 缓冲区、WiFi NVS 结构等,这个 WiFi 也启动 WiFi 任务。必须先调用此API,然后才能调用所有其他WiFi API) + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); + + // STA详细配置 + wifi_config_t sta_config = { + .sta = { + .ssid = ESP_WIFI_STA_SSID, + .password = ESP_WIFI_STA_PASSWD, + .bssid_set = false, + }, + }; + ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &sta_config)); + + //----------------启动阶段------------------- + ESP_ERROR_CHECK(esp_wifi_start()); + + //----------------配置省电模式------------------- + // 不省电(数据传输会更快) + ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE)); +} + + +// HTTP事件回调 +esp_err_t _http_event_handler(esp_http_client_event_t *evt) +{ + switch (evt->event_id) + { + case HTTP_EVENT_ERROR: // 错误事件 + ESP_LOGI(TAG, "HTTP_EVENT_ERROR"); + break; + case HTTP_EVENT_ON_CONNECTED: // 连接成功事件 + ESP_LOGI(TAG, "HTTP_EVENT_ON_CONNECTED"); + break; + case HTTP_EVENT_HEADER_SENT: // 发送头事件 + ESP_LOGI(TAG, "HTTP_EVENT_HEADER_SENT"); + break; + case HTTP_EVENT_ON_HEADER: // 接收头事件 + ESP_LOGI(TAG, "HTTP_EVENT_ON_HEADER"); + printf("%.*s", evt->data_len, (char *)evt->data); + break; + case HTTP_EVENT_ON_DATA: // 接收数据事件 + ESP_LOGI(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len); + if (!esp_http_client_is_chunked_response(evt->client)) + { + printf("%.*s", evt->data_len, (char *)evt->data); + } + break; + case HTTP_EVENT_ON_FINISH: // 会话完成事件 + ESP_LOGI(TAG, "HTTP_EVENT_ON_FINISH"); + break; + case HTTP_EVENT_DISCONNECTED: // 断开事件 + ESP_LOGI(TAG, "HTTP_EVENT_DISCONNECTED"); + break; + case HTTP_EVENT_REDIRECT: + ESP_LOGD(TAG, "HTTP_EVENT_REDIRECT"); + } + return ESP_OK; +} + + +// HTTP客户端任务 +static void http_client_task(void) +{ + // 等待wifi连接成功(暂时这样处理) + vTaskDelay(5000 / portTICK_PERIOD_MS); + ESP_LOGI("http_client_task", "http_client_task start"); + + // 初始化HTTP客户端 + char local_response_buffer[MAX_HTTP_OUTPUT_BUFFER + 1] = {0}; + + // 配置HTTP客户端目标 + esp_http_client_config_t config = { + //.method = HTTP_METHOD_GET, // get请求 + .url = "http://www.duruofu.top", // 请求url + .event_handler = _http_event_handler, // 事件回调 + .user_data = local_response_buffer, // Pass address of local buffer to get response + }; + esp_http_client_handle_t client = esp_http_client_init(&config); + + // GET + esp_http_client_set_method(client, HTTP_METHOD_GET); + esp_err_t err = esp_http_client_perform(client); + if (err == ESP_OK) + { + ESP_LOGI(TAG, "HTTP GET Status = %d, content_length = %" PRId64, + esp_http_client_get_status_code(client), + esp_http_client_get_content_length(client)); + } + else + { + ESP_LOGE(TAG, "HTTP GET request failed: %s", esp_err_to_name(err)); + } + ESP_LOG_BUFFER_HEX(TAG, local_response_buffer, strlen(local_response_buffer)); + + esp_http_client_cleanup(client); + + vTaskDelete(NULL); +} + +void app_main(void) +{ + // Initialize NVS + esp_err_t ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) + { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK(ret); + + // 创建默认事件循环 + ESP_ERROR_CHECK(esp_event_loop_create_default()); + + // 配置启动WIFI + wifi_sta_init(); + + // 创建HTTP客户端任务 + xTaskCreate(http_client_task, "http_client_task", 1024*8, NULL, 5, NULL); +} diff --git a/code/05.wifi/http/http_server/.gitignore b/code/05.wifi/http/http_server/.gitignore new file mode 100644 index 0000000..8da877b --- /dev/null +++ b/code/05.wifi/http/http_server/.gitignore @@ -0,0 +1,6 @@ +build +*managed_components +dependencies.lock +sdkconfig +sdkconfig.old + diff --git a/code/05.wifi/http/http_server/CMakeLists.txt b/code/05.wifi/http/http_server/CMakeLists.txt new file mode 100644 index 0000000..664d458 --- /dev/null +++ b/code/05.wifi/http/http_server/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(main) diff --git a/code/05.wifi/http/http_server/main/CMakeLists.txt b/code/05.wifi/http/http_server/main/CMakeLists.txt new file mode 100644 index 0000000..cf2c455 --- /dev/null +++ b/code/05.wifi/http/http_server/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") diff --git a/code/05.wifi/http/http_server/main/main.c b/code/05.wifi/http/http_server/main/main.c new file mode 100644 index 0000000..d932059 --- /dev/null +++ b/code/05.wifi/http/http_server/main/main.c @@ -0,0 +1,440 @@ +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/event_groups.h" +#include "esp_wifi.h" +#include "esp_log.h" +#include "esp_event.h" +#include +#include "nvs_flash.h" +#include "esp_mac.h" +#include "esp_netif.h" +#include +#include "esp_tls_crypto.h" +#include +#include "esp_tls.h" +#include "esp_check.h" +#include +#include +#include +#include +#include +#include +#include "esp_netif.h" +#include "esp_tls_crypto.h" +#include +#include "esp_event.h" +#include "esp_netif.h" +#include "esp_tls.h" +#include "esp_check.h" + +// 要连接的WIFI +#define ESP_WIFI_STA_SSID "duruofu_win10" +#define ESP_WIFI_STA_PASSWD "1234567890" + +static const char *TAG = "main"; + +#define EXAMPLE_HTTP_QUERY_KEY_MAX_LEN (64) + +char form_html[] = R"( + + + +ESP32 Web Server + + +

ESP32 Web Server

+
+
+
+
+

+ +
+ +)"; + +// WIFI回调 +void WIFI_CallBack(void *event_handler_arg, esp_event_base_t event_base, int32_t event_id, void *event_data) +{ + static uint8_t connect_count = 0; + // WIFI 启动成功 + if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) + { + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_START"); + ESP_ERROR_CHECK(esp_wifi_connect()); + } + // WIFI 连接失败 + if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) + { + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_DISCONNECTED"); + connect_count++; + if (connect_count < 6) + { + vTaskDelay(1000 / portTICK_PERIOD_MS); + ESP_ERROR_CHECK(esp_wifi_connect()); + } + else + { + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_DISCONNECTED 10 times"); + } + } + // WIFI 连接成功(获取到了IP) + if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) + { + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_GOT_IP"); + ip_event_got_ip_t *info = (ip_event_got_ip_t *)event_data; + ESP_LOGI("WIFI_EVENT", "got ip:" IPSTR "", IP2STR(&info->ip_info.ip)); + } +} + +// wifi初始化 +static void wifi_sta_init(void) +{ + ESP_ERROR_CHECK(esp_netif_init()); + + // 注册事件(wifi启动成功) + ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, WIFI_EVENT_STA_START, WIFI_CallBack, NULL, NULL)); + // 注册事件(wifi连接失败) + ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, WIFI_CallBack, NULL, NULL)); + // 注册事件(wifi连接失败) + ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, WIFI_CallBack, NULL, NULL)); + + // 初始化STA设备 + esp_netif_create_default_wifi_sta(); + + /*Initialize WiFi */ + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + // WIFI_INIT_CONFIG_DEFAULT 是一个默认配置的宏 + + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + + //----------------配置阶段------------------- + // 初始化WIFI设备( 为 WiFi 驱动初始化 WiFi 分配资源,如 WiFi 控制结构、RX/TX 缓冲区、WiFi NVS 结构等,这个 WiFi 也启动 WiFi 任务。必须先调用此API,然后才能调用所有其他WiFi API) + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); + + // STA详细配置 + wifi_config_t sta_config = { + .sta = { + .ssid = ESP_WIFI_STA_SSID, + .password = ESP_WIFI_STA_PASSWD, + .bssid_set = false, + }, + }; + ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &sta_config)); + + //----------------启动阶段------------------- + ESP_ERROR_CHECK(esp_wifi_start()); + + //----------------配置省电模式------------------- + // 不省电(数据传输会更快) + ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE)); +} + + +/*路由处理程序*/ + +/* An HTTP GET handler */ +static esp_err_t hello_get_handler(httpd_req_t *req) +{ + char *buf; + size_t buf_len; + + /* Get header value string length and allocate memory for length + 1, + * extra byte for null termination */ + buf_len = httpd_req_get_hdr_value_len(req, "Host") + 1; + if (buf_len > 1) + { + buf = malloc(buf_len); + ESP_RETURN_ON_FALSE(buf, ESP_ERR_NO_MEM, TAG, "buffer alloc failed"); + /* Copy null terminated value string into buffer */ + if (httpd_req_get_hdr_value_str(req, "Host", buf, buf_len) == ESP_OK) + { + ESP_LOGI(TAG, "Found header => Host: %s", buf); + } + free(buf); + } + + buf_len = httpd_req_get_hdr_value_len(req, "Test-Header-2") + 1; + if (buf_len > 1) + { + buf = malloc(buf_len); + ESP_RETURN_ON_FALSE(buf, ESP_ERR_NO_MEM, TAG, "buffer alloc failed"); + if (httpd_req_get_hdr_value_str(req, "Test-Header-2", buf, buf_len) == ESP_OK) + { + ESP_LOGI(TAG, "Found header => Test-Header-2: %s", buf); + } + free(buf); + } + + buf_len = httpd_req_get_hdr_value_len(req, "Test-Header-1") + 1; + if (buf_len > 1) + { + buf = malloc(buf_len); + ESP_RETURN_ON_FALSE(buf, ESP_ERR_NO_MEM, TAG, "buffer alloc failed"); + if (httpd_req_get_hdr_value_str(req, "Test-Header-1", buf, buf_len) == ESP_OK) + { + ESP_LOGI(TAG, "Found header => Test-Header-1: %s", buf); + } + free(buf); + } + + /* Read URL query string length and allocate memory for length + 1, + * extra byte for null termination */ + buf_len = httpd_req_get_url_query_len(req) + 1; + if (buf_len > 1) + { + buf = malloc(buf_len); + ESP_RETURN_ON_FALSE(buf, ESP_ERR_NO_MEM, TAG, "buffer alloc failed"); + if (httpd_req_get_url_query_str(req, buf, buf_len) == ESP_OK) + { + ESP_LOGI(TAG, "Found URL query => %s", buf); + char param[EXAMPLE_HTTP_QUERY_KEY_MAX_LEN], dec_param[EXAMPLE_HTTP_QUERY_KEY_MAX_LEN] = {0}; + /* Get value of expected key from query string */ + if (httpd_query_key_value(buf, "query1", param, sizeof(param)) == ESP_OK) + { + ESP_LOGI(TAG, "Found URL query parameter => query1=%s", param); + //example_uri_decode(dec_param, param, strnlen(param, EXAMPLE_HTTP_QUERY_KEY_MAX_LEN)); + ESP_LOGI(TAG, "Decoded query parameter => %s", dec_param); + } + if (httpd_query_key_value(buf, "query2", param, sizeof(param)) == ESP_OK) + { + ESP_LOGI(TAG, "Found URL query parameter => query2=%s", param); + //example_uri_decode(dec_param, param, strnlen(param, EXAMPLE_HTTP_QUERY_KEY_MAX_LEN)); + ESP_LOGI(TAG, "Decoded query parameter => %s", dec_param); + } + if (httpd_query_key_value(buf, "query3", param, sizeof(param)) == ESP_OK) + { + ESP_LOGI(TAG, "Found URL query parameter => query3=%s", param); + //example_uri_decode(dec_param, param, strnlen(param, EXAMPLE_HTTP_QUERY_KEY_MAX_LEN)); + ESP_LOGI(TAG, "Decoded query parameter => %s", dec_param); + } + } + free(buf); + } + + /* Set some custom headers */ + httpd_resp_set_hdr(req, "Custom-Header-1", "Custom-Value-1"); + httpd_resp_set_hdr(req, "Custom-Header-2", "Custom-Value-2"); + + /* Send response with custom headers and body set as the + * string passed in user context*/ + const char *resp_str = (const char *)req->user_ctx; + httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN); + + /* After sending the HTTP response the old HTTP request + * headers are lost. Check if HTTP request headers can be read now. */ + if (httpd_req_get_hdr_value_len(req, "Host") == 0) + { + ESP_LOGI(TAG, "Request headers lost"); + } + return ESP_OK; +} + +static esp_err_t html_get_handler(httpd_req_t *req) +{ + // 指向 HTML 页面字符串的指针 + const char *html_content = form_html; + + // 设置 Content-Type 头 + httpd_resp_set_type(req, "text/html"); + + // 发送 HTML 页面作为 HTTP 响应的正文部分 + httpd_resp_send(req, html_content, strlen(html_content)); + + return ESP_OK; +} + +/* An HTTP POST handler */ +static esp_err_t echo_post_handler(httpd_req_t *req) +{ + /* 定义 HTTP POST 请求数据的目标缓存区 + * httpd_req_recv() 只接收 char* 数据,但也可以是 + * 任意二进制数据(需要类型转换) + * 对于字符串数据,null 终止符会被省略, + * content_len 会给出字符串的长度 */ + char buf[100]; + int ret, remaining = req->content_len; + + while (remaining > 0) + { + /* Read the data for the request */ + if ((ret = httpd_req_recv(req, buf, + MIN(remaining, sizeof(buf)))) <= 0) + { + if (ret == HTTPD_SOCK_ERR_TIMEOUT) + { + /* Retry receiving if timeout occurred */ + continue; + } + /* 如果发生了错误,返回 ESP_FAIL 可以确保 + * 底层套接字被关闭 */ + return ESP_FAIL; + } + + /* Send back the same data */ + httpd_resp_send_chunk(req, buf, ret); + remaining -= ret; + + /* Log data received */ + ESP_LOGI(TAG, "=========== RECEIVED DATA =========="); + ESP_LOGI(TAG, "%.*s", ret, buf); + ESP_LOGI(TAG, "===================================="); + } + + // End response + httpd_resp_send_chunk(req, NULL, 0); + return ESP_OK; +} + +/* 注册路由 */ +const httpd_uri_t hello = { + .uri = "/hello", + .method = HTTP_GET, + .handler = hello_get_handler, + .user_ctx = "Hello World!"}; + +const httpd_uri_t html = { + .uri = "/html", + .method = HTTP_GET, + .handler = html_get_handler, + .user_ctx = NULL}; + +const httpd_uri_t echo = { + .uri = "/echo", + .method = HTTP_POST, + .handler = echo_post_handler, + .user_ctx = NULL}; + + +/* This handler allows the custom error handling functionality to be + * tested from client side. For that, when a PUT request 0 is sent to + * URI /ctrl, the /hello and /echo URIs are unregistered and following + * custom error handler http_404_error_handler() is registered. + * Afterwards, when /hello or /echo is requested, this custom error + * handler is invoked which, after sending an error message to client, + * either closes the underlying socket (when requested URI is /echo) + * or keeps it open (when requested URI is /hello). This allows the + * client to infer if the custom error handler is functioning as expected + * by observing the socket state. + */ +esp_err_t http_404_error_handler(httpd_req_t *req, httpd_err_code_t err) +{ + if (strcmp("/hello", req->uri) == 0) + { + httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "/hello URI is not available"); + /* Return ESP_OK to keep underlying socket open */ + return ESP_OK; + } + else if (strcmp("/echo", req->uri) == 0) + { + httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "/echo URI is not available"); + /* Return ESP_FAIL to close underlying socket */ + return ESP_FAIL; + } + /* For any other URI send 404 and close socket */ + httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "Some 404 error message"); + return ESP_FAIL; +} + +/* An HTTP PUT handler. This demonstrates realtime + * registration and deregistration of URI handlers + */ +esp_err_t ctrl_put_handler(httpd_req_t *req) +{ + char buf; + int ret; + + if ((ret = httpd_req_recv(req, &buf, 1)) <= 0) + { + if (ret == HTTPD_SOCK_ERR_TIMEOUT) + { + httpd_resp_send_408(req); + } + return ESP_FAIL; + } + + if (buf == '0') + { + /* URI handlers can be unregistered using the uri string */ + ESP_LOGI(TAG, "Unregistering /hello and /echo URIs"); + httpd_unregister_uri(req->handle, "/hello"); + httpd_unregister_uri(req->handle, "/echo"); + /* Register the custom error handler */ + httpd_register_err_handler(req->handle, HTTPD_404_NOT_FOUND, http_404_error_handler); + } + else + { + ESP_LOGI(TAG, "Registering /hello and /echo URIs"); + httpd_register_uri_handler(req->handle, &hello); + httpd_register_uri_handler(req->handle, &echo); + /* Unregister custom error handler */ + httpd_register_err_handler(req->handle, HTTPD_404_NOT_FOUND, NULL); + } + + /* Respond with empty body */ + httpd_resp_send(req, NULL, 0); + return ESP_OK; +} + + +static const httpd_uri_t ctrl = { + .uri = "/ctrl", + .method = HTTP_PUT, + .handler = ctrl_put_handler, + .user_ctx = NULL}; + +/* 启动 Web 服务器的函数 */ +httpd_handle_t start_webserver(void) +{ + /* 生成默认的配置参数 */ + httpd_config_t config = HTTPD_DEFAULT_CONFIG(); + + /* 置空 esp_http_server 的实例句柄 */ + httpd_handle_t server = NULL; + + ESP_LOGI(TAG, "Starting server on port: '%d'", config.server_port); + /* 启动 httpd server */ + if (httpd_start(&server, &config) == ESP_OK) + { + /* 注册 URI 处理程序 */ + ESP_LOGI(TAG, "Registering URI handlers"); + httpd_register_uri_handler(server, &hello); + httpd_register_uri_handler(server, &html); + httpd_register_uri_handler(server, &echo); + httpd_register_uri_handler(server, &ctrl); + } + /* 如果服务器启动失败,返回的句柄是 NULL */ + return server; +} + + +void app_main(void) +{ + static httpd_handle_t server = NULL; + + // Initialize NVS + esp_err_t ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) + { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK(ret); + + // 创建默认事件循环 + ESP_ERROR_CHECK(esp_event_loop_create_default()); + + // 配置启动WIFI + wifi_sta_init(); + + vTaskDelay(3000 / portTICK_PERIOD_MS); + + /* Start the server for the first time */ + server = start_webserver(); + + while (server) + { + sleep(5); + } +} diff --git a/code/05.wifi/mqtt/mqtt_tcp/.gitignore b/code/05.wifi/mqtt/mqtt_tcp/.gitignore new file mode 100644 index 0000000..8da877b --- /dev/null +++ b/code/05.wifi/mqtt/mqtt_tcp/.gitignore @@ -0,0 +1,6 @@ +build +*managed_components +dependencies.lock +sdkconfig +sdkconfig.old + diff --git a/code/05.wifi/mqtt/mqtt_tcp/CMakeLists.txt b/code/05.wifi/mqtt/mqtt_tcp/CMakeLists.txt new file mode 100644 index 0000000..664d458 --- /dev/null +++ b/code/05.wifi/mqtt/mqtt_tcp/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(main) diff --git a/code/05.wifi/mqtt/mqtt_tcp/main/CMakeLists.txt b/code/05.wifi/mqtt/mqtt_tcp/main/CMakeLists.txt new file mode 100644 index 0000000..cf2c455 --- /dev/null +++ b/code/05.wifi/mqtt/mqtt_tcp/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") diff --git a/code/05.wifi/mqtt/mqtt_tcp/main/main.c b/code/05.wifi/mqtt/mqtt_tcp/main/main.c new file mode 100644 index 0000000..c989d92 --- /dev/null +++ b/code/05.wifi/mqtt/mqtt_tcp/main/main.c @@ -0,0 +1,228 @@ +#include +#include +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/event_groups.h" +#include "esp_wifi.h" +#include "esp_log.h" +#include "esp_event.h" +#include "nvs_flash.h" +#include "esp_mac.h" +#include "esp_netif.h" +#include +#include "esp_eth.h" +#include "lwip/sockets.h" +#include "lwip/dns.h" +#include "lwip/netdb.h" +#include "mqtt_client.h" + + +// 要连接的WIFI +#define ESP_WIFI_STA_SSID "duruofu_win10" +#define ESP_WIFI_STA_PASSWD "1234567890" + +static const char *TAG = "main"; + + + +void WIFI_CallBack(void *event_handler_arg, esp_event_base_t event_base, int32_t event_id, void *event_data) +{ + static uint8_t connect_count = 0; + // WIFI 启动成功 + if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) + { + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_START"); + ESP_ERROR_CHECK(esp_wifi_connect()); + } + // WIFI 连接失败 + if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) + { + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_DISCONNECTED"); + connect_count++; + if (connect_count < 6) + { + vTaskDelay(1000 / portTICK_PERIOD_MS); + ESP_ERROR_CHECK(esp_wifi_connect()); + } + else + { + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_DISCONNECTED 10 times"); + } + } + // WIFI 连接成功(获取到了IP) + if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) + { + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_GOT_IP"); + ip_event_got_ip_t *info = (ip_event_got_ip_t *)event_data; + ESP_LOGI("WIFI_EVENT", "got ip:" IPSTR "", IP2STR(&info->ip_info.ip)); + } +} + +// wifi初始化 +static void wifi_sta_init(void) +{ + ESP_ERROR_CHECK(esp_netif_init()); + + // 注册事件(wifi启动成功) + ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, WIFI_EVENT_STA_START, WIFI_CallBack, NULL, NULL)); + // 注册事件(wifi连接失败) + ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, WIFI_CallBack, NULL, NULL)); + // 注册事件(wifi连接失败) + ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, WIFI_CallBack, NULL, NULL)); + + // 初始化STA设备 + esp_netif_create_default_wifi_sta(); + + /*Initialize WiFi */ + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + // WIFI_INIT_CONFIG_DEFAULT 是一个默认配置的宏 + + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + + //----------------配置阶段------------------- + // 初始化WIFI设备( 为 WiFi 驱动初始化 WiFi 分配资源,如 WiFi 控制结构、RX/TX 缓冲区、WiFi NVS 结构等,这个 WiFi 也启动 WiFi 任务。必须先调用此API,然后才能调用所有其他WiFi API) + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); + + // STA详细配置 + wifi_config_t sta_config = { + .sta = { + .ssid = ESP_WIFI_STA_SSID, + .password = ESP_WIFI_STA_PASSWD, + .bssid_set = false, + }, + }; + ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &sta_config)); + + //----------------启动阶段------------------- + ESP_ERROR_CHECK(esp_wifi_start()); + + //----------------配置省电模式------------------- + // 不省电(数据传输会更快) + ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE)); +} + +static void log_error_if_nonzero(const char *message, int error_code) +{ + if (error_code != 0) + { + ESP_LOGE(TAG, "Last error %s: 0x%x", message, error_code); + } +} + + +// MQTT客户端事件处理 +/* + * @brief Event handler registered to receive MQTT events + * + * This function is called by the MQTT client event loop. + * + * @param handler_args user data registered to the event. + * @param base Event base for the handler(always MQTT Base in this example). + * @param event_id The id for the received event. + * @param event_data The data for the event, esp_mqtt_event_handle_t. + */ +static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) +{ + ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%" PRIi32 "", base, event_id); + esp_mqtt_event_handle_t event = event_data; + esp_mqtt_client_handle_t client = event->client; + int msg_id; + switch ((esp_mqtt_event_id_t)event_id) + { + // MQTT连接成功 + case MQTT_EVENT_CONNECTED: + ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED"); + // 发布消息 + msg_id = esp_mqtt_client_publish(client, "/topic/qos1", "data_3", 0, 1, 0); + ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id); + // 订阅消息 + msg_id = esp_mqtt_client_subscribe(client, "/topic/qos0", 0); + ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id); + msg_id = esp_mqtt_client_subscribe(client, "/topic/qos1", 1); + ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id); + // 取消订阅消息 + msg_id = esp_mqtt_client_unsubscribe(client, "/topic/qos1"); + ESP_LOGI(TAG, "sent unsubscribe successful, msg_id=%d", msg_id); + break; + // MQTT连接断开 + case MQTT_EVENT_DISCONNECTED: + ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED"); + break; + // MQTT订阅成功 + case MQTT_EVENT_SUBSCRIBED: + ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id); + // 发布消息 + msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0); + ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id); + break; + // MQTT取消订阅成功 + case MQTT_EVENT_UNSUBSCRIBED: + ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id); + break; + // MQTT发布成功 + case MQTT_EVENT_PUBLISHED: + ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id); + break; + // MQTT收到数据 + case MQTT_EVENT_DATA: + ESP_LOGI(TAG, "MQTT_EVENT_DATA"); + printf("TOPIC=%.*s\r\n", event->topic_len, event->topic); + printf("DATA=%.*s\r\n", event->data_len, event->data); + break; + // MQTT错误 + case MQTT_EVENT_ERROR: + ESP_LOGI(TAG, "MQTT_EVENT_ERROR"); + if (event->error_handle->error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT) + { + log_error_if_nonzero("reported from esp-tls", event->error_handle->esp_tls_last_esp_err); + log_error_if_nonzero("reported from tls stack", event->error_handle->esp_tls_stack_err); + log_error_if_nonzero("captured as transport's socket errno", event->error_handle->esp_transport_sock_errno); + ESP_LOGI(TAG, "Last errno string (%s)", strerror(event->error_handle->esp_transport_sock_errno)); + } + break; + default: + ESP_LOGI(TAG, "Other event id:%d", event->event_id); + break; + } +} + +// MQTT客户端 +static void mqtt_app_start(void) +{ + esp_mqtt_client_config_t mqtt_cfg = { + .broker.address.uri = "mqtt://www.duruofu.top:1883", + }; + + esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg); + /* The last argument may be used to pass data to the event handler, in this example mqtt_event_handler */ + // 注册事件处理函数 + esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL); + // 启动MQTT客户端 + esp_mqtt_client_start(client); +} + +void app_main(void) +{ + + // Initialize NVS + esp_err_t ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) + { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK(ret); + + // 创建默认事件循环 + ESP_ERROR_CHECK(esp_event_loop_create_default()); + + // 配置启动WIFI + wifi_sta_init(); + + // 等待wifi连接成功(暂时这样处理) + vTaskDelay(5000 / portTICK_PERIOD_MS); + + // 创建MQTT客户端 + mqtt_app_start(); +} diff --git a/code/05.wifi/mqtt/mqtt_ws/.gitignore b/code/05.wifi/mqtt/mqtt_ws/.gitignore new file mode 100644 index 0000000..8da877b --- /dev/null +++ b/code/05.wifi/mqtt/mqtt_ws/.gitignore @@ -0,0 +1,6 @@ +build +*managed_components +dependencies.lock +sdkconfig +sdkconfig.old + diff --git a/code/05.wifi/mqtt/mqtt_ws/CMakeLists.txt b/code/05.wifi/mqtt/mqtt_ws/CMakeLists.txt new file mode 100644 index 0000000..664d458 --- /dev/null +++ b/code/05.wifi/mqtt/mqtt_ws/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(main) diff --git a/code/05.wifi/mqtt/mqtt_ws/main/CMakeLists.txt b/code/05.wifi/mqtt/mqtt_ws/main/CMakeLists.txt new file mode 100644 index 0000000..cf2c455 --- /dev/null +++ b/code/05.wifi/mqtt/mqtt_ws/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") diff --git a/code/05.wifi/mqtt/mqtt_ws/main/main.c b/code/05.wifi/mqtt/mqtt_ws/main/main.c new file mode 100644 index 0000000..7b66f33 --- /dev/null +++ b/code/05.wifi/mqtt/mqtt_ws/main/main.c @@ -0,0 +1,6 @@ +#include + +void app_main(void) +{ + +} diff --git a/code/05.wifi/sntp/.gitignore b/code/05.wifi/sntp/.gitignore new file mode 100644 index 0000000..8da877b --- /dev/null +++ b/code/05.wifi/sntp/.gitignore @@ -0,0 +1,6 @@ +build +*managed_components +dependencies.lock +sdkconfig +sdkconfig.old + diff --git a/code/05.wifi/sntp/CMakeLists.txt b/code/05.wifi/sntp/CMakeLists.txt new file mode 100644 index 0000000..664d458 --- /dev/null +++ b/code/05.wifi/sntp/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(main) diff --git a/code/05.wifi/sntp/main/CMakeLists.txt b/code/05.wifi/sntp/main/CMakeLists.txt new file mode 100644 index 0000000..cf2c455 --- /dev/null +++ b/code/05.wifi/sntp/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") diff --git a/code/05.wifi/sntp/main/main.c b/code/05.wifi/sntp/main/main.c new file mode 100644 index 0000000..fe472d7 --- /dev/null +++ b/code/05.wifi/sntp/main/main.c @@ -0,0 +1,188 @@ +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/event_groups.h" +#include "esp_wifi.h" +#include "esp_log.h" +#include "esp_event.h" +#include "nvs_flash.h" +#include "esp_mac.h" +#include "esp_netif.h" +#include +#include "esp_netif_sntp.h" +#include "lwip/ip_addr.h" +#include "esp_sntp.h" + +// 要连接的WIFI +#define ESP_WIFI_STA_SSID "duruofu" +#define ESP_WIFI_STA_PASSWD "1234567890" + + +static const char *TAG = "main"; + +void time_sync_notification_cb(struct timeval *tv) +{ + ESP_LOGI(TAG, "Notification of a time synchronization event"); +} + +static void print_servers(void) +{ + ESP_LOGI(TAG, "List of configured NTP servers:"); + + for (uint8_t i = 0; i < SNTP_MAX_SERVERS; ++i) + { + if (esp_sntp_getservername(i)) + { + ESP_LOGI(TAG, "server %d: %s", i, esp_sntp_getservername(i)); + } + else + { + // we have either IPv4 or IPv6 address, let's print it + char buff[INET6_ADDRSTRLEN]; + ip_addr_t const *ip = esp_sntp_getserver(i); + if (ipaddr_ntoa_r(ip, buff, INET6_ADDRSTRLEN) != NULL) + ESP_LOGI(TAG, "server %d: %s", i, buff); + } + } +} + +static void obtain_time(void) +{ + // Set timezone to Beijing time + setenv("TZ", "CST-8", 1); // CST-8 represents China Standard Time (UTC+8) + tzset(); + + ESP_LOGI(TAG, "Initializing SNTP"); + esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG("cn.pool.ntp.org"); + config.sync_cb = time_sync_notification_cb; + config.renew_servers_after_new_IP = true, + + // Initialize SNTP with the provided configuration + esp_netif_sntp_init(&config); + + // Start SNTP + esp_netif_sntp_start(); + + ESP_LOGI(TAG, "Initializing and starting SNTP"); + + print_servers(); + + // wait for time to be set + time_t now = 0; + struct tm timeinfo = {0}; + int retry = 0; + const int retry_count = 15; + while (esp_netif_sntp_sync_wait(2000 / portTICK_PERIOD_MS) == ESP_ERR_TIMEOUT && ++retry < retry_count) + { + ESP_LOGI(TAG, "Waiting for system time to be set... (%d/%d)", retry, retry_count); + } + time(&now); + localtime_r(&now, &timeinfo); + + + + // Print current time + char strftime_buf[64]; + strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo); + ESP_LOGI(TAG, "Current time: %s", strftime_buf); +} + + +void WIFI_CallBack(void *event_handler_arg, esp_event_base_t event_base, int32_t event_id, void *event_data) +{ + static uint8_t connect_count = 0; + // WIFI 启动成功 + if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) + { + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_START"); + ESP_ERROR_CHECK(esp_wifi_connect()); + } + // WIFI 连接失败 + if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) + { + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_DISCONNECTED"); + connect_count++; + if (connect_count < 6) + { + vTaskDelay(1000 / portTICK_PERIOD_MS); + ESP_ERROR_CHECK(esp_wifi_connect()); + } + else + { + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_DISCONNECTED 10 times"); + } + } + // WIFI 连接成功(获取到了IP) + if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) + { + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_GOT_IP"); + ip_event_got_ip_t *info = (ip_event_got_ip_t *)event_data; + ESP_LOGI("WIFI_EVENT", "got ip:" IPSTR "", IP2STR(&info->ip_info.ip)); + // 更新时间 + obtain_time(); + } +} + +// wifi初始化 +static void wifi_sta_init(void) +{ + ESP_ERROR_CHECK(esp_netif_init()); + + // 注册事件(wifi启动成功) + ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, WIFI_EVENT_STA_START, WIFI_CallBack, NULL, NULL)); + // 注册事件(wifi连接失败) + ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, WIFI_CallBack, NULL, NULL)); + // 注册事件(wifi连接失败) + ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, WIFI_CallBack, NULL, NULL)); + + // 初始化STA设备 + esp_netif_create_default_wifi_sta(); + + /*Initialize WiFi */ + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + // WIFI_INIT_CONFIG_DEFAULT 是一个默认配置的宏 + + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + + //----------------配置阶段------------------- + // 初始化WIFI设备( 为 WiFi 驱动初始化 WiFi 分配资源,如 WiFi 控制结构、RX/TX 缓冲区、WiFi NVS 结构等,这个 WiFi 也启动 WiFi 任务。必须先调用此API,然后才能调用所有其他WiFi API) + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); + + // STA详细配置 + wifi_config_t sta_config = { + .sta = { + .ssid = ESP_WIFI_STA_SSID, + .password = ESP_WIFI_STA_PASSWD, + .bssid_set = false, + }, + }; + ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &sta_config)); + + //----------------启动阶段------------------- + ESP_ERROR_CHECK(esp_wifi_start()); + + //----------------配置省电模式------------------- + // 不省电(数据传输会更快) + ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE)); +} + + +void app_main(void) +{ + // Initialize NVS + esp_err_t ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) + { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK(ret); + + // 创建默认事件循环 + ESP_ERROR_CHECK(esp_event_loop_create_default()); + + // 配置启动WIFI + wifi_sta_init(); + + +} diff --git a/code/05.wifi/tcp/wifi_tcp_client/.gitignore b/code/05.wifi/tcp/wifi_tcp_client/.gitignore new file mode 100644 index 0000000..8da877b --- /dev/null +++ b/code/05.wifi/tcp/wifi_tcp_client/.gitignore @@ -0,0 +1,6 @@ +build +*managed_components +dependencies.lock +sdkconfig +sdkconfig.old + diff --git a/code/05.wifi/tcp/wifi_tcp_client/CMakeLists.txt b/code/05.wifi/tcp/wifi_tcp_client/CMakeLists.txt new file mode 100644 index 0000000..664d458 --- /dev/null +++ b/code/05.wifi/tcp/wifi_tcp_client/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(main) diff --git a/code/05.wifi/tcp/wifi_tcp_client/main/CMakeLists.txt b/code/05.wifi/tcp/wifi_tcp_client/main/CMakeLists.txt new file mode 100644 index 0000000..cf2c455 --- /dev/null +++ b/code/05.wifi/tcp/wifi_tcp_client/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") diff --git a/code/05.wifi/tcp/wifi_tcp_client/main/main.c b/code/05.wifi/tcp/wifi_tcp_client/main/main.c new file mode 100644 index 0000000..f9e6026 --- /dev/null +++ b/code/05.wifi/tcp/wifi_tcp_client/main/main.c @@ -0,0 +1,185 @@ +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/event_groups.h" +#include "esp_wifi.h" +#include "esp_log.h" +#include "esp_event.h" +#include "nvs_flash.h" +#include "esp_mac.h" +#include "esp_netif.h" +#include + +#define ESP_WIFI_STA_SSID "duruofu_win10" +#define ESP_WIFI_STA_PASSWD "1234567890" +#define TCP_SREVER_ADDR "192.168.137.1" +#define TCP_SREVER_PORT 8080 + +static const char *TAG = "main"; + +void WIFI_CallBack(void *event_handler_arg, esp_event_base_t event_base, int32_t event_id, void *event_data) +{ + static uint8_t connect_count = 0; + // WIFI 启动成功 + if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) + { + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_START"); + ESP_ERROR_CHECK(esp_wifi_connect()); + } + // WIFI 连接失败 + if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) + { + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_DISCONNECTED"); + connect_count++; + if (connect_count < 6) + { + vTaskDelay(1000 / portTICK_PERIOD_MS); + ESP_ERROR_CHECK(esp_wifi_connect()); + } + else + { + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_DISCONNECTED 10 times"); + } + } + // WIFI 连接成功(获取到了IP) + if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) + { + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_GOT_IP"); + ip_event_got_ip_t *info = (ip_event_got_ip_t *)event_data; + ESP_LOGI("WIFI_EVENT", "got ip:" IPSTR "", IP2STR(&info->ip_info.ip)); + } +} + +static void tcp_client_task(void *pvParameters) +{ + + + // 等待wifi连接成功(暂时这样处理) + vTaskDelay(5000 / portTICK_PERIOD_MS); + + ESP_LOGI("tcp_client_task", "tcp_client_task start"); + + // 创建socket + int sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) // 创建失败返回-1 + { + ESP_LOGE(TAG, "Unable to create socket: errno %d", errno); + return; + } + + // 设置服务器(IPV4) + struct sockaddr_in server_config; + server_config.sin_addr.s_addr = inet_addr(TCP_SREVER_ADDR); + server_config.sin_family = AF_INET; + server_config.sin_port = htons(TCP_SREVER_PORT); // 宏htons 用于将主机的无符号短整型数据转换成网络字节顺序(小端转大端) + + // 连接服务器 + int err = connect(sock, (struct sockaddr *)&server_config, sizeof(server_config)); + if (err != 0) + { + ESP_LOGE(TAG, "Socket unable to connect: errno %d", errno); + return; + } + + // 发送数据 + const char *data = "Hello World!"; + int len = send(sock, data, strlen(data), 0); + if (len < 0) + { + ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno); + return; + } + + char rx_buffer[1024]; + // 接收数据,并发回 + while(1) + { + int len = recv(sock, rx_buffer, sizeof(rx_buffer), 0); + // Error occurred during receiving + if (len < 0) + { + ESP_LOGE(TAG, "recv failed: errno %d", errno); + break; + } + // Data received + else + { + ESP_LOGI(TAG, "Received %d bytes from %s:", len, TCP_SREVER_ADDR); + ESP_LOGI(TAG, "%.*s", len, rx_buffer); + + // 发送数据 + int len_end = send(sock, rx_buffer, len, 0); + if (len_end < 0) + { + ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno); + break; + } + } + } + + vTaskDelete(NULL); +} + +// wifi初始化 +static void wifi_sta_init(void) +{ + ESP_ERROR_CHECK(esp_netif_init()); + + // 注册事件(wifi启动成功) + ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, WIFI_EVENT_STA_START, WIFI_CallBack, NULL, NULL)); + // 注册事件(wifi连接失败) + ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, WIFI_CallBack, NULL, NULL)); + // 注册事件(wifi连接失败) + ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, WIFI_CallBack, NULL, NULL)); + + // 初始化STA设备 + esp_netif_create_default_wifi_sta(); + + /*Initialize WiFi */ + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + // WIFI_INIT_CONFIG_DEFAULT 是一个默认配置的宏 + + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + + //----------------配置阶段------------------- + // 初始化WIFI设备( 为 WiFi 驱动初始化 WiFi 分配资源,如 WiFi 控制结构、RX/TX 缓冲区、WiFi NVS 结构等,这个 WiFi 也启动 WiFi 任务。必须先调用此API,然后才能调用所有其他WiFi API) + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); + + // STA详细配置 + wifi_config_t sta_config = { + .sta = { + .ssid = ESP_WIFI_STA_SSID, + .password = ESP_WIFI_STA_PASSWD, + .bssid_set = false, + }, + }; + ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &sta_config)); + + //----------------启动阶段------------------- + ESP_ERROR_CHECK(esp_wifi_start()); + + //----------------配置省电模式------------------- + // 不省电(数据传输会更快) + ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE)); +} + +void app_main(void) +{ + // Initialize NVS + esp_err_t ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) + { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK(ret); + + // 创建默认事件循环 + ESP_ERROR_CHECK(esp_event_loop_create_default()); + + // 配置启动WIFI + wifi_sta_init(); + + // 创建TCP客户端任务 + xTaskCreate(tcp_client_task, "tcp_client_task", 4096, NULL, 5, NULL); +} diff --git a/code/05.wifi/tcp/wifi_tcp_server/.gitignore b/code/05.wifi/tcp/wifi_tcp_server/.gitignore new file mode 100644 index 0000000..8da877b --- /dev/null +++ b/code/05.wifi/tcp/wifi_tcp_server/.gitignore @@ -0,0 +1,6 @@ +build +*managed_components +dependencies.lock +sdkconfig +sdkconfig.old + diff --git a/code/05.wifi/tcp/wifi_tcp_server/CMakeLists.txt b/code/05.wifi/tcp/wifi_tcp_server/CMakeLists.txt new file mode 100644 index 0000000..664d458 --- /dev/null +++ b/code/05.wifi/tcp/wifi_tcp_server/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(main) diff --git a/code/05.wifi/tcp/wifi_tcp_server/main/CMakeLists.txt b/code/05.wifi/tcp/wifi_tcp_server/main/CMakeLists.txt new file mode 100644 index 0000000..cf2c455 --- /dev/null +++ b/code/05.wifi/tcp/wifi_tcp_server/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") diff --git a/code/05.wifi/tcp/wifi_tcp_server/main/main.c b/code/05.wifi/tcp/wifi_tcp_server/main/main.c new file mode 100644 index 0000000..d1aab81 --- /dev/null +++ b/code/05.wifi/tcp/wifi_tcp_server/main/main.c @@ -0,0 +1,240 @@ +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/event_groups.h" +#include "esp_wifi.h" +#include "esp_log.h" +#include "esp_event.h" +#include "nvs_flash.h" +#include "esp_mac.h" +#include "esp_netif.h" +#include + +#define ESP_WIFI_STA_SSID "duruofu_win10" +#define ESP_WIFI_STA_PASSWD "1234567890" + +#define TCP_SREVER_PORT 8080 + +static const char *TAG = "main"; + +void WIFI_CallBack(void *event_handler_arg, esp_event_base_t event_base, int32_t event_id, void *event_data) +{ + static uint8_t connect_count = 0; + // WIFI 启动成功 + if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) + { + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_START"); + ESP_ERROR_CHECK(esp_wifi_connect()); + } + // WIFI 连接失败 + if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) + { + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_DISCONNECTED"); + connect_count++; + if (connect_count < 6) + { + vTaskDelay(1000 / portTICK_PERIOD_MS); + ESP_ERROR_CHECK(esp_wifi_connect()); + } + else + { + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_DISCONNECTED 10 times"); + } + } + // WIFI 连接成功(获取到了IP) + if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) + { + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_GOT_IP"); + ip_event_got_ip_t *info = (ip_event_got_ip_t *)event_data; + ESP_LOGI("WIFI_EVENT", "got ip:" IPSTR "", IP2STR(&info->ip_info.ip)); + } +} + +// 数据接收与回传 +static void do_retransmit(const int sock) +{ + int len; + char rx_buffer[128]; + + do + { + len = recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0); + if (len < 0) + { + ESP_LOGE(TAG, "Error occurred during receiving: errno %d", errno); + } + else if (len == 0) + { + ESP_LOGW(TAG, "Connection closed"); + } + else + { + rx_buffer[len] = 0; // Null-terminate whatever is received and treat it like a string + ESP_LOGI(TAG, "Received %d bytes: %s", len, rx_buffer); + + // send() can return less bytes than supplied length. + // Walk-around for robust implementation. + int to_write = len; + while (to_write > 0) + { + int written = send(sock, rx_buffer + (len - to_write), to_write, 0); + if (written < 0) + { + ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno); + // Failed to retransmit, giving up + return; + } + to_write -= written; + } + } + } while (len > 0); +} + +// tcp服务器任务 +static void tcp_server_task(void *pvParameters) +{ + // 创建套接字 + int listen_sock = socket(AF_INET, SOCK_STREAM, 0); + if (listen_sock < 0) + { + ESP_LOGE(TAG, "Unable to create socket: errno %d", errno); + vTaskDelete(NULL); + return; + } + // 设置套接字属性 + int opt = 1; + setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); + ESP_LOGI(TAG, "Socket created"); + + // 设置服务器(IPV4) + struct sockaddr_storage dest_addr; + struct sockaddr_in *dest_addr_ip4 = (struct sockaddr_in *)&dest_addr; + dest_addr_ip4->sin_addr.s_addr = htonl(INADDR_ANY); + dest_addr_ip4->sin_family = AF_INET; + dest_addr_ip4->sin_port = htons(TCP_SREVER_PORT); + + // 绑定套接字 + int err = bind(listen_sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr)); + if (err != 0) + { + ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno); + ESP_LOGE(TAG, "IPPROTO: %d", AF_INET); + goto CLEAN_UP; + } + ESP_LOGI(TAG, "Socket bound, port %d", TCP_SREVER_PORT); + + // 监听套接字 (阻塞) + err = listen(listen_sock, 1); + if (err != 0) + { + ESP_LOGE(TAG, "Error occurred during listen: errno %d", errno); + goto CLEAN_UP; + } + + while (1) + { + char addr_str[128]; + + ESP_LOGI(TAG, "Socket listening"); + struct sockaddr_storage source_addr; // Large enough for both IPv4 or IPv6 + socklen_t addr_len = sizeof(source_addr); + int sock = accept(listen_sock, (struct sockaddr *)&source_addr, &addr_len); + if (sock < 0) + { + ESP_LOGE(TAG, "Unable to accept connection: errno %d", errno); + break; + } + + // Set tcp keepalive option + int keepAlive = 1; + int keepIdle = 5; // TCP keep-alive idle time(s) + int keepInterval = 5; // TCP keep-alive interval time(s) + int keepCount = 3; // TCP keep-alive packet retry send counts + + setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &keepAlive, sizeof(int)); + setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &keepIdle, sizeof(int)); + setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &keepInterval, sizeof(int)); + setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &keepCount, sizeof(int)); + + // Convert ip address to string + if (source_addr.ss_family == PF_INET) + { + inet_ntoa_r(((struct sockaddr_in *)&source_addr)->sin_addr, addr_str, sizeof(addr_str) - 1); + } + + ESP_LOGI(TAG, "Socket accepted ip address: %s", addr_str); + + do_retransmit(sock); + + shutdown(sock, 0); + close(sock); + } + +CLEAN_UP: + close(listen_sock); + vTaskDelete(NULL); +} + +// wifi初始化 +static void wifi_sta_init(void) +{ + ESP_ERROR_CHECK(esp_netif_init()); + + // 注册事件(wifi启动成功) + ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, WIFI_EVENT_STA_START, WIFI_CallBack, NULL, NULL)); + // 注册事件(wifi连接失败) + ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, WIFI_CallBack, NULL, NULL)); + // 注册事件(wifi连接失败) + ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, WIFI_CallBack, NULL, NULL)); + + // 初始化STA设备 + esp_netif_create_default_wifi_sta(); + + /*Initialize WiFi */ + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + // WIFI_INIT_CONFIG_DEFAULT 是一个默认配置的宏 + + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + + //----------------配置阶段------------------- + // 初始化WIFI设备( 为 WiFi 驱动初始化 WiFi 分配资源,如 WiFi 控制结构、RX/TX 缓冲区、WiFi NVS 结构等,这个 WiFi 也启动 WiFi 任务。必须先调用此API,然后才能调用所有其他WiFi API) + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); + + // STA详细配置 + wifi_config_t sta_config = { + .sta = { + .ssid = ESP_WIFI_STA_SSID, + .password = ESP_WIFI_STA_PASSWD, + .bssid_set = false, + }, + }; + ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &sta_config)); + + //----------------启动阶段------------------- + ESP_ERROR_CHECK(esp_wifi_start()); + + //----------------配置省电模式------------------- + // 不省电(数据传输会更快) + ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE)); +} + +void app_main(void) +{ + // Initialize NVS + esp_err_t ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) + { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK(ret); + + // 创建默认事件循环 + ESP_ERROR_CHECK(esp_event_loop_create_default()); + + // 配置启动WIFI + wifi_sta_init(); + + // 创建TCP服务器任务 + xTaskCreate(tcp_server_task, "tcp_server_task", 4096, NULL, 5, NULL); +} diff --git a/code/05.wifi/udp/wifi_udp_client/.gitignore b/code/05.wifi/udp/wifi_udp_client/.gitignore new file mode 100644 index 0000000..8da877b --- /dev/null +++ b/code/05.wifi/udp/wifi_udp_client/.gitignore @@ -0,0 +1,6 @@ +build +*managed_components +dependencies.lock +sdkconfig +sdkconfig.old + diff --git a/code/05.wifi/udp/wifi_udp_client/CMakeLists.txt b/code/05.wifi/udp/wifi_udp_client/CMakeLists.txt new file mode 100644 index 0000000..664d458 --- /dev/null +++ b/code/05.wifi/udp/wifi_udp_client/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(main) diff --git a/code/05.wifi/udp/wifi_udp_client/main/CMakeLists.txt b/code/05.wifi/udp/wifi_udp_client/main/CMakeLists.txt new file mode 100644 index 0000000..cf2c455 --- /dev/null +++ b/code/05.wifi/udp/wifi_udp_client/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") diff --git a/code/05.wifi/udp/wifi_udp_client/main/main.c b/code/05.wifi/udp/wifi_udp_client/main/main.c new file mode 100644 index 0000000..5fa4f67 --- /dev/null +++ b/code/05.wifi/udp/wifi_udp_client/main/main.c @@ -0,0 +1,176 @@ +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/event_groups.h" +#include "esp_wifi.h" +#include "esp_log.h" +#include "esp_event.h" +#include "nvs_flash.h" +#include "esp_mac.h" +#include "esp_netif.h" +#include + +// 要连接的WIFI +#define ESP_WIFI_STA_SSID "duruofu_win10" +#define ESP_WIFI_STA_PASSWD "1234567890" + +// 目标服务器地址端口 +#define UDP_SREVER_ADDR "255.255.255.255" +#define UDP_SREVER_PORT 8080 + +static const char *TAG = "main"; + +void WIFI_CallBack(void *event_handler_arg, esp_event_base_t event_base, int32_t event_id, void *event_data) +{ + static uint8_t connect_count = 0; + // WIFI 启动成功 + if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) + { + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_START"); + ESP_ERROR_CHECK(esp_wifi_connect()); + } + // WIFI 连接失败 + if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) + { + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_DISCONNECTED"); + connect_count++; + if (connect_count < 6) + { + vTaskDelay(1000 / portTICK_PERIOD_MS); + ESP_ERROR_CHECK(esp_wifi_connect()); + } + else + { + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_DISCONNECTED 10 times"); + } + } + // WIFI 连接成功(获取到了IP) + if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) + { + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_GOT_IP"); + ip_event_got_ip_t *info = (ip_event_got_ip_t *)event_data; + ESP_LOGI("WIFI_EVENT", "got ip:" IPSTR "", IP2STR(&info->ip_info.ip)); + } +} + +// udp客户端 +static void udp_client_task(void *pvParameters) +{ + // 等待wifi连接成功(暂时这样处理) + vTaskDelay(5000 / portTICK_PERIOD_MS); + ESP_LOGI("udp_client_task", "udp_client_task start"); + + // 创建socket + int sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock < 0) // 创建失败返回-1 + { + ESP_LOGE(TAG, "Unable to create socket: errno %d", errno); + return; + } + + // 设置服务器(IPV4) + struct sockaddr_in server_config; + server_config.sin_addr.s_addr = inet_addr(UDP_SREVER_ADDR); + server_config.sin_family = AF_INET; + server_config.sin_port = htons(UDP_SREVER_PORT); // 宏htons 用于将主机的无符号短整型数据转换成网络字节顺序(小端转大端) + + + // 发送数据 + const char *data = "Hello World!"; + int err = sendto(sock, data, strlen(data), 0, (struct sockaddr *)&server_config, sizeof(server_config)); + if (err < 0) + { + ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno); + close(sock); + } + + char rx_buffer[1024]; + // 接收数据,并发回 + while(1) + { + // 清空缓存 + memset(rx_buffer, 0, sizeof(rx_buffer)); + // 接收数据 + + struct sockaddr_in source_addr; + socklen_t socklen = sizeof(source_addr); + int len = recvfrom(sock, rx_buffer, sizeof(rx_buffer) - 1, 0, (struct sockaddr *)&source_addr, &socklen); + if (len < 0) + { + ESP_LOGE(TAG, "Error occurred during receiving: errno %d", errno); + break; + } + else + { + // 打印接收到的数据 + ESP_LOGI(TAG, "Received %d bytes: %s", len, rx_buffer); + } + } + // 关闭socket + close(sock); + vTaskDelete(NULL); +} + +// wifi初始化 +static void wifi_sta_init(void) +{ + ESP_ERROR_CHECK(esp_netif_init()); + + // 注册事件(wifi启动成功) + ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, WIFI_EVENT_STA_START, WIFI_CallBack, NULL, NULL)); + // 注册事件(wifi连接失败) + ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, WIFI_CallBack, NULL, NULL)); + // 注册事件(wifi连接失败) + ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, WIFI_CallBack, NULL, NULL)); + + // 初始化STA设备 + esp_netif_create_default_wifi_sta(); + + /*Initialize WiFi */ + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + // WIFI_INIT_CONFIG_DEFAULT 是一个默认配置的宏 + + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + + //----------------配置阶段------------------- + // 初始化WIFI设备( 为 WiFi 驱动初始化 WiFi 分配资源,如 WiFi 控制结构、RX/TX 缓冲区、WiFi NVS 结构等,这个 WiFi 也启动 WiFi 任务。必须先调用此API,然后才能调用所有其他WiFi API) + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); + + // STA详细配置 + wifi_config_t sta_config = { + .sta = { + .ssid = ESP_WIFI_STA_SSID, + .password = ESP_WIFI_STA_PASSWD, + .bssid_set = false, + }, + }; + ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &sta_config)); + + //----------------启动阶段------------------- + ESP_ERROR_CHECK(esp_wifi_start()); + + //----------------配置省电模式------------------- + // 不省电(数据传输会更快) + ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE)); +} + +void app_main(void) +{ + // Initialize NVS + esp_err_t ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) + { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK(ret); + + // 创建默认事件循环 + ESP_ERROR_CHECK(esp_event_loop_create_default()); + + // 配置启动WIFI + wifi_sta_init(); + + // 创建TCP客户端任务 + xTaskCreate(udp_client_task, "udp_client_task", 4096, NULL, 5, NULL); +} diff --git a/code/05.wifi/udp/wifi_udp_server/.gitignore b/code/05.wifi/udp/wifi_udp_server/.gitignore new file mode 100644 index 0000000..8da877b --- /dev/null +++ b/code/05.wifi/udp/wifi_udp_server/.gitignore @@ -0,0 +1,6 @@ +build +*managed_components +dependencies.lock +sdkconfig +sdkconfig.old + diff --git a/code/05.wifi/udp/wifi_udp_server/CMakeLists.txt b/code/05.wifi/udp/wifi_udp_server/CMakeLists.txt new file mode 100644 index 0000000..664d458 --- /dev/null +++ b/code/05.wifi/udp/wifi_udp_server/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(main) diff --git a/code/05.wifi/udp/wifi_udp_server/main/CMakeLists.txt b/code/05.wifi/udp/wifi_udp_server/main/CMakeLists.txt new file mode 100644 index 0000000..cf2c455 --- /dev/null +++ b/code/05.wifi/udp/wifi_udp_server/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") diff --git a/code/05.wifi/udp/wifi_udp_server/main/main.c b/code/05.wifi/udp/wifi_udp_server/main/main.c new file mode 100644 index 0000000..f0a7add --- /dev/null +++ b/code/05.wifi/udp/wifi_udp_server/main/main.c @@ -0,0 +1,185 @@ +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/event_groups.h" +#include "esp_wifi.h" +#include "esp_log.h" +#include "esp_event.h" +#include "nvs_flash.h" +#include "esp_mac.h" +#include "esp_netif.h" +#include +#include "lwip/err.h" +#include "lwip/sys.h" +#include + + +// 要连接的WIFI +#define ESP_WIFI_STA_SSID "duruofu_win10" +#define ESP_WIFI_STA_PASSWD "1234567890" + +// 服务器端口 +#define UDP_SREVER_PORT 8080 + +static const char *TAG = "main"; + +void WIFI_CallBack(void *event_handler_arg, esp_event_base_t event_base, int32_t event_id, void *event_data) +{ + static uint8_t connect_count = 0; + // WIFI 启动成功 + if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) + { + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_START"); + ESP_ERROR_CHECK(esp_wifi_connect()); + } + // WIFI 连接失败 + if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) + { + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_DISCONNECTED"); + connect_count++; + if (connect_count < 6) + { + vTaskDelay(1000 / portTICK_PERIOD_MS); + ESP_ERROR_CHECK(esp_wifi_connect()); + } + else + { + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_DISCONNECTED 10 times"); + } + } + // WIFI 连接成功(获取到了IP) + if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) + { + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_GOT_IP"); + ip_event_got_ip_t *info = (ip_event_got_ip_t *)event_data; + ESP_LOGI("WIFI_EVENT", "got ip:" IPSTR "", IP2STR(&info->ip_info.ip)); + } +} + +// udp客户端 +static void udp_server_task(void *pvParameters) +{ + // 等待wifi连接成功(暂时这样处理) + vTaskDelay(5000 / portTICK_PERIOD_MS); + ESP_LOGI("udp_server_task", "udp_server_task start"); + + // 创建socket + int sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock < 0) // 创建失败返回-1 + { + ESP_LOGE(TAG, "Unable to create socket: errno %d", errno); + return; + } + + // 设置服务器(IPV4) + struct sockaddr_in server_config; + server_config.sin_addr.s_addr = htonl(INADDR_ANY); + server_config.sin_family = AF_INET; + server_config.sin_port = htons(UDP_SREVER_PORT); // 宏htons 用于将主机的无符号短整型数据转换成网络字节顺序(小端转大端) + + // 绑定端口 + int err = bind(sock, (struct sockaddr *)&server_config, sizeof(server_config)); + if (err < 0) + { + ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno); + } + ESP_LOGI(TAG, "Socket bound, port %d", UDP_SREVER_PORT); + + char rx_buffer[1024]; + // 接收数据,并发回 + while(1) + { + // 清空缓存 + memset(rx_buffer, 0, sizeof(rx_buffer)); + // 接收数据 + + struct sockaddr_in source_addr; + socklen_t socklen = sizeof(source_addr); + int len = recvfrom(sock, rx_buffer, sizeof(rx_buffer) - 1, 0, (struct sockaddr *)&source_addr, &socklen); + if (len < 0) + { + ESP_LOGE(TAG, "Error occurred during receiving: errno %d", errno); + break; + } + else + { + // 打印接收到的数据 + ESP_LOGI(TAG, "Received %d bytes: %s", len, rx_buffer); + // 发送数据 + int err = sendto(sock, rx_buffer, len, 0, (struct sockaddr *)&source_addr, sizeof(source_addr)); + if (err < 0) + { + ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno); + break; + } + ESP_LOGI(TAG, "Send success"); + } + } + // 关闭socket + close(sock); + vTaskDelete(NULL); +} + +// wifi初始化 +static void wifi_sta_init(void) +{ + ESP_ERROR_CHECK(esp_netif_init()); + + // 注册事件(wifi启动成功) + ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, WIFI_EVENT_STA_START, WIFI_CallBack, NULL, NULL)); + // 注册事件(wifi连接失败) + ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, WIFI_CallBack, NULL, NULL)); + // 注册事件(wifi连接失败) + ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, WIFI_CallBack, NULL, NULL)); + + // 初始化STA设备 + esp_netif_create_default_wifi_sta(); + + /*Initialize WiFi */ + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + // WIFI_INIT_CONFIG_DEFAULT 是一个默认配置的宏 + + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + + //----------------配置阶段------------------- + // 初始化WIFI设备( 为 WiFi 驱动初始化 WiFi 分配资源,如 WiFi 控制结构、RX/TX 缓冲区、WiFi NVS 结构等,这个 WiFi 也启动 WiFi 任务。必须先调用此API,然后才能调用所有其他WiFi API) + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); + + // STA详细配置 + wifi_config_t sta_config = { + .sta = { + .ssid = ESP_WIFI_STA_SSID, + .password = ESP_WIFI_STA_PASSWD, + .bssid_set = false, + }, + }; + ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &sta_config)); + + //----------------启动阶段------------------- + ESP_ERROR_CHECK(esp_wifi_start()); + + //----------------配置省电模式------------------- + // 不省电(数据传输会更快) + ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE)); +} + +void app_main(void) +{ + // Initialize NVS + esp_err_t ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) + { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK(ret); + + // 创建默认事件循环 + ESP_ERROR_CHECK(esp_event_loop_create_default()); + + // 配置启动WIFI + wifi_sta_init(); + + // 创建TCP客户端任务 + xTaskCreate(udp_server_task, "udp_server_task", 4096, NULL, 5, NULL); +} diff --git a/code/05.wifi/websocket/client/.gitignore b/code/05.wifi/websocket/client/.gitignore new file mode 100644 index 0000000..8da877b --- /dev/null +++ b/code/05.wifi/websocket/client/.gitignore @@ -0,0 +1,6 @@ +build +*managed_components +dependencies.lock +sdkconfig +sdkconfig.old + diff --git a/code/05.wifi/websocket/client/CMakeLists.txt b/code/05.wifi/websocket/client/CMakeLists.txt new file mode 100644 index 0000000..664d458 --- /dev/null +++ b/code/05.wifi/websocket/client/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(main) diff --git a/code/05.wifi/websocket/client/main/CMakeLists.txt b/code/05.wifi/websocket/client/main/CMakeLists.txt new file mode 100644 index 0000000..cf2c455 --- /dev/null +++ b/code/05.wifi/websocket/client/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") diff --git a/code/05.wifi/websocket/client/main/idf_component.yml b/code/05.wifi/websocket/client/main/idf_component.yml new file mode 100644 index 0000000..8f99a94 --- /dev/null +++ b/code/05.wifi/websocket/client/main/idf_component.yml @@ -0,0 +1,17 @@ +## IDF Component Manager Manifest File +dependencies: + espressif/esp_websocket_client: "^1.2.2" + ## Required IDF version + idf: + version: ">=4.1.0" + # # Put list of dependencies here + # # For components maintained by Espressif: + # component: "~1.0.0" + # # For 3rd party components: + # username/component: ">=1.0.0,<2.0.0" + # username2/component2: + # version: "~1.0.0" + # # For transient dependencies `public` flag can be set. + # # `public` flag doesn't have an effect dependencies of the `main` component. + # # All dependencies of `main` are public by default. + # public: true diff --git a/code/05.wifi/websocket/client/main/main.c b/code/05.wifi/websocket/client/main/main.c new file mode 100644 index 0000000..b3f7dbb --- /dev/null +++ b/code/05.wifi/websocket/client/main/main.c @@ -0,0 +1,264 @@ +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/event_groups.h" +#include "esp_wifi.h" +#include "esp_log.h" +#include "esp_event.h" +#include "nvs_flash.h" +#include "esp_mac.h" +#include "esp_netif.h" +#include +#include "esp_eth.h" +#include "esp_websocket_client.h" +#include + +// 要连接的WIFI +#define ESP_WIFI_STA_SSID "duruofu_win10" +#define ESP_WIFI_STA_PASSWD "1234567890" + +// 目标服务器 +#define CONFIG_WEBSOCKET_URI "ws://192.168.137.1:5000" +#define NO_DATA_TIMEOUT_SEC 5 + +static const char *TAG = "main"; + +static TimerHandle_t shutdown_signal_timer; +static SemaphoreHandle_t shutdown_sema; + +void WIFI_CallBack(void *event_handler_arg, esp_event_base_t event_base, int32_t event_id, void *event_data) +{ + static uint8_t connect_count = 0; + // WIFI 启动成功 + if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) + { + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_START"); + ESP_ERROR_CHECK(esp_wifi_connect()); + } + // WIFI 连接失败 + if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) + { + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_DISCONNECTED"); + connect_count++; + if (connect_count < 6) + { + vTaskDelay(1000 / portTICK_PERIOD_MS); + ESP_ERROR_CHECK(esp_wifi_connect()); + } + else + { + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_DISCONNECTED 10 times"); + } + } + // WIFI 连接成功(获取到了IP) + if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) + { + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_GOT_IP"); + ip_event_got_ip_t *info = (ip_event_got_ip_t *)event_data; + ESP_LOGI("WIFI_EVENT", "got ip:" IPSTR "", IP2STR(&info->ip_info.ip)); + } +} + +// wifi初始化 +static void wifi_sta_init(void) +{ + ESP_ERROR_CHECK(esp_netif_init()); + + // 注册事件(wifi启动成功) + ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, WIFI_EVENT_STA_START, WIFI_CallBack, NULL, NULL)); + // 注册事件(wifi连接失败) + ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, WIFI_CallBack, NULL, NULL)); + // 注册事件(wifi连接失败) + ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, WIFI_CallBack, NULL, NULL)); + + // 初始化STA设备 + esp_netif_create_default_wifi_sta(); + + /*Initialize WiFi */ + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + // WIFI_INIT_CONFIG_DEFAULT 是一个默认配置的宏 + + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + + //----------------配置阶段------------------- + // 初始化WIFI设备( 为 WiFi 驱动初始化 WiFi 分配资源,如 WiFi 控制结构、RX/TX 缓冲区、WiFi NVS 结构等,这个 WiFi 也启动 WiFi 任务。必须先调用此API,然后才能调用所有其他WiFi API) + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); + + // STA详细配置 + wifi_config_t sta_config = { + .sta = { + .ssid = ESP_WIFI_STA_SSID, + .password = ESP_WIFI_STA_PASSWD, + .bssid_set = false, + }, + }; + ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &sta_config)); + + //----------------启动阶段------------------- + ESP_ERROR_CHECK(esp_wifi_start()); + + //----------------配置省电模式------------------- + // 不省电(数据传输会更快) + ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE)); +} + +static void log_error_if_nonzero(const char *message, int error_code) +{ + if (error_code != 0) + { + ESP_LOGE(TAG, "Last error %s: 0x%x", message, error_code); + } +} + +static void shutdown_signaler(TimerHandle_t xTimer) +{ + ESP_LOGI(TAG, "No data received for %d seconds, signaling shutdown", NO_DATA_TIMEOUT_SEC); + xSemaphoreGive(shutdown_sema); +} + +// WebSocket客户端事件处理 +static void websocket_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) +{ + esp_websocket_event_data_t *data = (esp_websocket_event_data_t *)event_data; + switch (event_id) + { + // 连接成功 + case WEBSOCKET_EVENT_CONNECTED: + ESP_LOGI(TAG, "WEBSOCKET_EVENT_CONNECTED"); + break; + // 连接断开 + case WEBSOCKET_EVENT_DISCONNECTED: + ESP_LOGI(TAG, "WEBSOCKET_EVENT_DISCONNECTED"); + log_error_if_nonzero("HTTP status code", data->error_handle.esp_ws_handshake_status_code); + if (data->error_handle.error_type == WEBSOCKET_ERROR_TYPE_TCP_TRANSPORT) + { + log_error_if_nonzero("reported from esp-tls", data->error_handle.esp_tls_last_esp_err); + log_error_if_nonzero("reported from tls stack", data->error_handle.esp_tls_stack_err); + log_error_if_nonzero("captured as transport's socket errno", data->error_handle.esp_transport_sock_errno); + } + break; + // 收到数据 + case WEBSOCKET_EVENT_DATA: + ESP_LOGI(TAG, "WEBSOCKET_EVENT_DATA"); + ESP_LOGI(TAG, "Received opcode=%d", data->op_code); + if (data->op_code == 0x08 && data->data_len == 2) + { + ESP_LOGW(TAG, "Received closed message with code=%d", 256 * data->data_ptr[0] + data->data_ptr[1]); + } + else + { + ESP_LOGW(TAG, "Received=%.*s\n\n", data->data_len, (char *)data->data_ptr); + } + + // If received data contains json structure it succeed to parse + cJSON *root = cJSON_Parse(data->data_ptr); + if (root) + { + for (int i = 0; i < cJSON_GetArraySize(root); i++) + { + cJSON *elem = cJSON_GetArrayItem(root, i); + cJSON *id = cJSON_GetObjectItem(elem, "id"); + cJSON *name = cJSON_GetObjectItem(elem, "name"); + ESP_LOGW(TAG, "Json={'id': '%s', 'name': '%s'}", id->valuestring, name->valuestring); + } + cJSON_Delete(root); + } + + ESP_LOGW(TAG, "Total payload length=%d, data_len=%d, current payload offset=%d\r\n", data->payload_len, data->data_len, data->payload_offset); + + // 定时器复位 + xTimerReset(shutdown_signal_timer, portMAX_DELAY); + break; + // 错误 + case WEBSOCKET_EVENT_ERROR: + ESP_LOGI(TAG, "WEBSOCKET_EVENT_ERROR"); + log_error_if_nonzero("HTTP status code", data->error_handle.esp_ws_handshake_status_code); + if (data->error_handle.error_type == WEBSOCKET_ERROR_TYPE_TCP_TRANSPORT) + { + log_error_if_nonzero("reported from esp-tls", data->error_handle.esp_tls_last_esp_err); + log_error_if_nonzero("reported from tls stack", data->error_handle.esp_tls_stack_err); + log_error_if_nonzero("captured as transport's socket errno", data->error_handle.esp_transport_sock_errno); + } + break; + } +} + +// WebSocket客户端 +static void websocket_app_start(void) +{ + esp_websocket_client_config_t websocket_cfg = {}; + + // 创建定时器 + shutdown_signal_timer = xTimerCreate("Websocket shutdown timer", NO_DATA_TIMEOUT_SEC * 1000 / portTICK_PERIOD_MS, + pdFALSE, NULL, shutdown_signaler); + // 创建信号量 + shutdown_sema = xSemaphoreCreateBinary(); + + // 配置目标服务器 + websocket_cfg.uri = CONFIG_WEBSOCKET_URI; + + ESP_LOGI(TAG, "Connecting to %s...", websocket_cfg.uri); + + // 创建WebSocket客户端 + esp_websocket_client_handle_t client = esp_websocket_client_init(&websocket_cfg); + // 注册事件 + esp_websocket_register_events(client, WEBSOCKET_EVENT_ANY, websocket_event_handler, (void *)client); + // 启动WebSocket客户端 + esp_websocket_client_start(client); + xTimerStart(shutdown_signal_timer, portMAX_DELAY); + char data[32]; + int i = 0; + // 发送5次数据 + while (i < 5) + { + if (esp_websocket_client_is_connected(client)) + { + int len = sprintf(data, "hello %04d", i++); + ESP_LOGI(TAG, "Sending %s", data); + // 发送文本数据 + esp_websocket_client_send_text(client, data, len, portMAX_DELAY); + } + vTaskDelay(1000 / portTICK_PERIOD_MS); + } + + ESP_LOGI(TAG, "Sending fragmented message"); + vTaskDelay(1000 / portTICK_PERIOD_MS); + memset(data, 'a', sizeof(data)); + esp_websocket_client_send_text_partial(client, data, sizeof(data), portMAX_DELAY); + memset(data, 'b', sizeof(data)); + esp_websocket_client_send_cont_msg(client, data, sizeof(data), portMAX_DELAY); + esp_websocket_client_send_fin(client, portMAX_DELAY); + + // 等待信号量 + xSemaphoreTake(shutdown_sema, portMAX_DELAY); + // 关闭WebSocket客户端 + esp_websocket_client_close(client, portMAX_DELAY); + ESP_LOGI(TAG, "Websocket Stopped"); + // 销毁WebSocket客户端 + esp_websocket_client_destroy(client); +} + +void app_main(void) +{ + + // Initialize NVS + esp_err_t ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) + { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK(ret); + + // 创建默认事件循环 + ESP_ERROR_CHECK(esp_event_loop_create_default()); + + // 配置启动WIFI + wifi_sta_init(); + + // 等待wifi连接成功(暂时这样处理) + vTaskDelay(5000 / portTICK_PERIOD_MS); + + // 创建WebSocket客户端 + websocket_app_start(); +} diff --git a/code/05.wifi/websocket/client/websocket_echo_server.py b/code/05.wifi/websocket/client/websocket_echo_server.py new file mode 100644 index 0000000..91cb1bb --- /dev/null +++ b/code/05.wifi/websocket/client/websocket_echo_server.py @@ -0,0 +1,18 @@ +from flask import Flask +from flask_sock import Sock + +app = Flask(__name__) +sock = Sock(app) + + +@sock.route('/') +def echo(ws): + while True: + data = ws.receive() + ws.send(data) + + +if __name__ == '__main__': + # To run your Flask + WebSocket server in production you can use Gunicorn: + # gunicorn -b 0.0.0.0:5000 --workers 4 --threads 100 module:app + app.run(host="0.0.0.0", debug=True) diff --git a/code/05.wifi/websocket/server/.gitignore b/code/05.wifi/websocket/server/.gitignore new file mode 100644 index 0000000..8da877b --- /dev/null +++ b/code/05.wifi/websocket/server/.gitignore @@ -0,0 +1,6 @@ +build +*managed_components +dependencies.lock +sdkconfig +sdkconfig.old + diff --git a/code/05.wifi/websocket/server/CMakeLists.txt b/code/05.wifi/websocket/server/CMakeLists.txt new file mode 100644 index 0000000..664d458 --- /dev/null +++ b/code/05.wifi/websocket/server/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(main) diff --git a/code/05.wifi/websocket/server/main/CMakeLists.txt b/code/05.wifi/websocket/server/main/CMakeLists.txt new file mode 100644 index 0000000..cf2c455 --- /dev/null +++ b/code/05.wifi/websocket/server/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") diff --git a/code/05.wifi/websocket/server/main/main.c b/code/05.wifi/websocket/server/main/main.c new file mode 100644 index 0000000..c3b8e08 --- /dev/null +++ b/code/05.wifi/websocket/server/main/main.c @@ -0,0 +1,262 @@ +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/event_groups.h" +#include "esp_wifi.h" +#include "esp_log.h" +#include "esp_event.h" +#include "nvs_flash.h" +#include "esp_mac.h" +#include "esp_netif.h" +#include +#include +#include "esp_eth.h" + +// 要连接的WIFI +#define ESP_WIFI_STA_SSID "duruofu_win10" +#define ESP_WIFI_STA_PASSWD "1234567890" + +static const char *TAG = "main"; + +void WIFI_CallBack(void *event_handler_arg, esp_event_base_t event_base, int32_t event_id, void *event_data) +{ + static uint8_t connect_count = 0; + // WIFI 启动成功 + if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) + { + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_START"); + ESP_ERROR_CHECK(esp_wifi_connect()); + } + // WIFI 连接失败 + if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) + { + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_DISCONNECTED"); + connect_count++; + if (connect_count < 6) + { + vTaskDelay(1000 / portTICK_PERIOD_MS); + ESP_ERROR_CHECK(esp_wifi_connect()); + } + else + { + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_DISCONNECTED 10 times"); + } + } + // WIFI 连接成功(获取到了IP) + if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) + { + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_GOT_IP"); + ip_event_got_ip_t *info = (ip_event_got_ip_t *)event_data; + ESP_LOGI("WIFI_EVENT", "got ip:" IPSTR "", IP2STR(&info->ip_info.ip)); + } +} + +// wifi初始化 +static void wifi_sta_init(void) +{ + ESP_ERROR_CHECK(esp_netif_init()); + + // 注册事件(wifi启动成功) + ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, WIFI_EVENT_STA_START, WIFI_CallBack, NULL, NULL)); + // 注册事件(wifi连接失败) + ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, WIFI_CallBack, NULL, NULL)); + // 注册事件(wifi连接失败) + ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, WIFI_CallBack, NULL, NULL)); + + // 初始化STA设备 + esp_netif_create_default_wifi_sta(); + + /*Initialize WiFi */ + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + // WIFI_INIT_CONFIG_DEFAULT 是一个默认配置的宏 + + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + + //----------------配置阶段------------------- + // 初始化WIFI设备( 为 WiFi 驱动初始化 WiFi 分配资源,如 WiFi 控制结构、RX/TX 缓冲区、WiFi NVS 结构等,这个 WiFi 也启动 WiFi 任务。必须先调用此API,然后才能调用所有其他WiFi API) + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); + + // STA详细配置 + wifi_config_t sta_config = { + .sta = { + .ssid = ESP_WIFI_STA_SSID, + .password = ESP_WIFI_STA_PASSWD, + .bssid_set = false, + }, + }; + ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &sta_config)); + + //----------------启动阶段------------------- + ESP_ERROR_CHECK(esp_wifi_start()); + + //----------------配置省电模式------------------- + // 不省电(数据传输会更快) + ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE)); +} + +/* + * Structure holding server handle + * and internal socket fd in order + * to use out of request send + */ +struct async_resp_arg +{ + httpd_handle_t hd; + int fd; +}; + +/* + * async send function, which we put into the httpd work queue + */ +static void ws_async_send(void *arg) +{ + static const char *data = "Async data"; + struct async_resp_arg *resp_arg = arg; + httpd_handle_t hd = resp_arg->hd; + int fd = resp_arg->fd; + httpd_ws_frame_t ws_pkt; + memset(&ws_pkt, 0, sizeof(httpd_ws_frame_t)); + ws_pkt.payload = (uint8_t *)data; + ws_pkt.len = strlen(data); + ws_pkt.type = HTTPD_WS_TYPE_TEXT; + + httpd_ws_send_frame_async(hd, fd, &ws_pkt); + free(resp_arg); +} + +static esp_err_t trigger_async_send(httpd_handle_t handle, httpd_req_t *req) +{ + struct async_resp_arg *resp_arg = malloc(sizeof(struct async_resp_arg)); + if (resp_arg == NULL) + { + return ESP_ERR_NO_MEM; + } + resp_arg->hd = req->handle; + resp_arg->fd = httpd_req_to_sockfd(req); + esp_err_t ret = httpd_queue_work(handle, ws_async_send, resp_arg); + if (ret != ESP_OK) + { + free(resp_arg); + } + return ret; +} + +/* + * This handler echos back the received ws data + * and triggers an async send if certain message received + */ +static esp_err_t echo_handler(httpd_req_t *req) +{ + if (req->method == HTTP_GET) + { + ESP_LOGI(TAG, "Handshake done, the new connection was opened"); + return ESP_OK; + } + httpd_ws_frame_t ws_pkt; + uint8_t *buf = NULL; + memset(&ws_pkt, 0, sizeof(httpd_ws_frame_t)); + ws_pkt.type = HTTPD_WS_TYPE_TEXT; + /* Set max_len = 0 to get the frame len */ + // 读取数据 + esp_err_t ret = httpd_ws_recv_frame(req, &ws_pkt, 0); + if (ret != ESP_OK) + { + ESP_LOGE(TAG, "httpd_ws_recv_frame failed to get frame len with %d", ret); + return ret; + } + ESP_LOGI(TAG, "frame len is %d", ws_pkt.len); + if (ws_pkt.len) + { + /* ws_pkt.len + 1 is for NULL termination as we are expecting a string */ + buf = calloc(1, ws_pkt.len + 1); + if (buf == NULL) + { + ESP_LOGE(TAG, "Failed to calloc memory for buf"); + return ESP_ERR_NO_MEM; + } + ws_pkt.payload = buf; + /* Set max_len = ws_pkt.len to get the frame payload */ + ret = httpd_ws_recv_frame(req, &ws_pkt, ws_pkt.len); + if (ret != ESP_OK) + { + ESP_LOGE(TAG, "httpd_ws_recv_frame failed with %d", ret); + free(buf); + return ret; + } + ESP_LOGI(TAG, "Got packet with message: %s", ws_pkt.payload); + } + ESP_LOGI(TAG, "Packet type: %d", ws_pkt.type); + // 发送数据 + if (ws_pkt.type == HTTPD_WS_TYPE_TEXT && + strcmp((char *)ws_pkt.payload, "Trigger async") == 0) + { + free(buf); + return trigger_async_send(req->handle, req); + } + + ret = httpd_ws_send_frame(req, &ws_pkt); + if (ret != ESP_OK) + { + ESP_LOGE(TAG, "httpd_ws_send_frame failed with %d", ret); + } + free(buf); + return ret; +} + +static const httpd_uri_t ws = { + .uri = "/ws", + .method = HTTP_GET, + .handler = echo_handler, + .user_ctx = NULL, + .is_websocket = true}; + +static httpd_handle_t start_webserver(void) +{ + httpd_handle_t server = NULL; + httpd_config_t config = HTTPD_DEFAULT_CONFIG(); + + // Start the httpd server + ESP_LOGI(TAG, "Starting server on port: '%d'", config.server_port); + if (httpd_start(&server, &config) == ESP_OK) + { + // Registering the ws handler + ESP_LOGI(TAG, "Registering URI handlers"); + httpd_register_uri_handler(server, &ws); + return server; + } + + ESP_LOGI(TAG, "Error starting server!"); + return NULL; +} + +static esp_err_t stop_webserver(httpd_handle_t server) +{ + // Stop the httpd server + return httpd_stop(server); +} + +void app_main(void) +{ + static httpd_handle_t server = NULL; + + // Initialize NVS + esp_err_t ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) + { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK(ret); + + // 创建默认事件循环 + ESP_ERROR_CHECK(esp_event_loop_create_default()); + + // 配置启动WIFI + wifi_sta_init(); + + // 等待wifi连接成功(暂时这样处理) + vTaskDelay(5000 / portTICK_PERIOD_MS); + + // 创建WebSocket服务器 + server = start_webserver(); +} diff --git a/code/05.wifi/wifi_ap/.gitignore b/code/05.wifi/wifi_ap/.gitignore new file mode 100644 index 0000000..8da877b --- /dev/null +++ b/code/05.wifi/wifi_ap/.gitignore @@ -0,0 +1,6 @@ +build +*managed_components +dependencies.lock +sdkconfig +sdkconfig.old + diff --git a/code/05.wifi/wifi_ap/CMakeLists.txt b/code/05.wifi/wifi_ap/CMakeLists.txt new file mode 100644 index 0000000..664d458 --- /dev/null +++ b/code/05.wifi/wifi_ap/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(main) diff --git a/code/05.wifi/wifi_ap/main/CMakeLists.txt b/code/05.wifi/wifi_ap/main/CMakeLists.txt new file mode 100644 index 0000000..cf2c455 --- /dev/null +++ b/code/05.wifi/wifi_ap/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") diff --git a/code/05.wifi/wifi_ap/main/main.c b/code/05.wifi/wifi_ap/main/main.c new file mode 100644 index 0000000..4b9cb56 --- /dev/null +++ b/code/05.wifi/wifi_ap/main/main.c @@ -0,0 +1,83 @@ +#include +#include "freertos/FreeRTOS.h" +#include "freertos/event_groups.h" +#include "esp_wifi.h" +#include "esp_log.h" +#include "esp_event.h" +#include "nvs_flash.h" +#include "esp_mac.h" + +#define ESP_WIFI_AP_SSID "DuRuofu_ESP32" +#define ESP_WIFI_AP_PASSWD "3.1415926" + +void WIFI_CallBack(void *event_handler_arg,esp_event_base_t event_base,int32_t event_id,void *event_data) +{ + // 连接事件 + if(event_base == IP_EVENT && event_id == IP_EVENT_AP_STAIPASSIGNED) + { + // 解析数据 + ip_event_ap_staipassigned_t* event_info = (ip_event_ap_staipassigned_t *)event_data; + ESP_LOGW("WIFI_AP", "设备已连接 MAC:"MACSTR"", MAC2STR(event_info->mac)); + } + + // 断开连接事件 + if(event_base == WIFI_EVENT && event_id == WIFI_EVENT_AP_STADISCONNECTED) + { + wifi_event_ap_stadisconnected_t* event_info = (wifi_event_ap_stadisconnected_t*)event_data; + ESP_LOGW("WIFI_AP", "设备已断开 MAC:"MACSTR"", MAC2STR(event_info->mac)); + } +} + +void app_main(void) +{ + //----------------准备阶段------------------- + // Initialize NVS + esp_err_t ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) + { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK(ret); + + //---------------初始化阶段------------------ + + ESP_ERROR_CHECK(esp_netif_init()); + + // 初始化默认事件循环 + ESP_ERROR_CHECK(esp_event_loop_create_default()); + // 注册设备连接事件回调 + esp_event_handler_instance_register(IP_EVENT, IP_EVENT_AP_STAIPASSIGNED, WIFI_CallBack, NULL, NULL); + // 注册设备断开连接设备回调 + esp_event_handler_instance_register(WIFI_EVENT, WIFI_EVENT_AP_STADISCONNECTED, WIFI_CallBack, NULL, NULL); + + // *esp_netif_ap 可以用来修改AP设置 + esp_netif_t *esp_netif_ap = esp_netif_create_default_wifi_ap(); + + /*Initialize WiFi */ + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + // WIFI_INIT_CONFIG_DEFAULT 是一个默认配置的宏 + // 初始化WIFI设备( 为 WiFi 驱动初始化 WiFi 分配资源,如 WiFi 控制结构、RX/TX 缓冲区、WiFi NVS 结构等,这个 WiFi 也启动 WiFi 任务。必须先调用此API,然后才能调用所有其他WiFi API) + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + + //---------------配置阶段-------------------- + // 设置为AP模式 + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP)); + + // AP详细配置 + wifi_config_t wifi_ap_config = { + .ap = { + .ssid = ESP_WIFI_AP_SSID, // WIFI名称 + .ssid_len = strlen(ESP_WIFI_AP_SSID), // 名称长度 + .channel = 1, // WIFI信道 + .password = ESP_WIFI_AP_PASSWD, // WiFi密码 + .max_connection = 5, // 最大连接数,默认值是 10 + .authmode = WIFI_AUTH_WPA2_PSK, // WiFi认证方式 + }, + }; + ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_ap_config)); + + //---------------启动阶段-------------------- + /* Start WiFi */ + ESP_ERROR_CHECK(esp_wifi_start()); +} diff --git a/code/05.wifi/wifi_scan/.gitignore b/code/05.wifi/wifi_scan/.gitignore new file mode 100644 index 0000000..8da877b --- /dev/null +++ b/code/05.wifi/wifi_scan/.gitignore @@ -0,0 +1,6 @@ +build +*managed_components +dependencies.lock +sdkconfig +sdkconfig.old + diff --git a/code/05.wifi/wifi_scan/CMakeLists.txt b/code/05.wifi/wifi_scan/CMakeLists.txt new file mode 100644 index 0000000..664d458 --- /dev/null +++ b/code/05.wifi/wifi_scan/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(main) diff --git a/code/05.wifi/wifi_scan/main/CMakeLists.txt b/code/05.wifi/wifi_scan/main/CMakeLists.txt new file mode 100644 index 0000000..cf2c455 --- /dev/null +++ b/code/05.wifi/wifi_scan/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") diff --git a/code/05.wifi/wifi_scan/main/main.c b/code/05.wifi/wifi_scan/main/main.c new file mode 100644 index 0000000..7bd2091 --- /dev/null +++ b/code/05.wifi/wifi_scan/main/main.c @@ -0,0 +1,183 @@ +#includ +#include +#include "freertos/FreeRTOS.h" +#include "freertos/event_groups.h" +#include "esp_wifi.h" +#include "esp_log.h" +#include "esp_event.h" +#include "nvs_flash.h" +#include "esp_mac.h" +#include "esp_netif.h" + +#define ESP_WIFI_STA_SSID "duruofu_win10" +#define ESP_WIFI_STA_PASSWD "1234567890" + +// 扫面列表大小 +#define DEFAULT_SCAN_LIST_SIZE 10 + +static const char *TAG = "wifi_scan"; + +// 打印加密模式 +static void print_auth_mode(int authmode) +{ + switch (authmode) + { + case WIFI_AUTH_OPEN: + ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_OPEN"); + break; + case WIFI_AUTH_OWE: + ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_OWE"); + break; + case WIFI_AUTH_WEP: + ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WEP"); + break; + case WIFI_AUTH_WPA_PSK: + ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WPA_PSK"); + break; + case WIFI_AUTH_WPA2_PSK: + ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WPA2_PSK"); + break; + case WIFI_AUTH_WPA_WPA2_PSK: + ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WPA_WPA2_PSK"); + break; + case WIFI_AUTH_WPA2_ENTERPRISE: + ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WPA2_ENTERPRISE"); + break; + case WIFI_AUTH_WPA3_PSK: + ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WPA3_PSK"); + break; + case WIFI_AUTH_WPA2_WPA3_PSK: + ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_WPA2_WPA3_PSK"); + break; + default: + ESP_LOGI(TAG, "Authmode \tWIFI_AUTH_UNKNOWN"); + break; + } +} + +// 打印密码类型 +static void print_cipher_type(int pairwise_cipher, int group_cipher) +{ + switch (pairwise_cipher) + { + case WIFI_CIPHER_TYPE_NONE: + ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_NONE"); + break; + case WIFI_CIPHER_TYPE_WEP40: + ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_WEP40"); + break; + case WIFI_CIPHER_TYPE_WEP104: + ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_WEP104"); + break; + case WIFI_CIPHER_TYPE_TKIP: + ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_TKIP"); + break; + case WIFI_CIPHER_TYPE_CCMP: + ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_CCMP"); + break; + case WIFI_CIPHER_TYPE_TKIP_CCMP: + ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_TKIP_CCMP"); + break; + default: + ESP_LOGI(TAG, "Pairwise Cipher \tWIFI_CIPHER_TYPE_UNKNOWN"); + break; + } + + switch (group_cipher) + { + case WIFI_CIPHER_TYPE_NONE: + ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_NONE"); + break; + case WIFI_CIPHER_TYPE_WEP40: + ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_WEP40"); + break; + case WIFI_CIPHER_TYPE_WEP104: + ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_WEP104"); + break; + case WIFI_CIPHER_TYPE_TKIP: + ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_TKIP"); + break; + case WIFI_CIPHER_TYPE_CCMP: + ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_CCMP"); + break; + case WIFI_CIPHER_TYPE_TKIP_CCMP: + ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_TKIP_CCMP"); + break; + default: + ESP_LOGI(TAG, "Group Cipher \tWIFI_CIPHER_TYPE_UNKNOWN"); + break; + } +} + +void app_main(void) +{ + //----------------准备阶段------------------- + // Initialize NVS + esp_err_t ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) + { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK(ret); + + //----------------初始化阶段------------------- + ESP_ERROR_CHECK(esp_netif_init()); + + ESP_ERROR_CHECK(esp_event_loop_create_default()); + + // 初始化WIFI设备( 为 WiFi 驱动初始化 WiFi 分配资源,如 WiFi 控制结构、RX/TX 缓冲区、WiFi NVS 结构等,这个 WiFi 也启动 WiFi 任务。必须先调用此API,然后才能调用所有其他WiFi API) + esp_netif_t *sta_netif = esp_netif_create_default_wifi_sta(); + assert(sta_netif); + + /*Initialize WiFi */ + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + // WIFI_INIT_CONFIG_DEFAULT 是一个默认配置的宏 + + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + + //----------------配置阶段------------------- + // 设置为STA模式 + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); + + // STA详细配置 + wifi_config_t sta_config = { + .sta = { + .ssid = ESP_WIFI_STA_SSID, + .password = ESP_WIFI_STA_PASSWD, + .bssid_set = false, + }, + }; + ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &sta_config)); + + //----------------启动阶段------------------- + ESP_ERROR_CHECK(esp_wifi_start()); + + //----------------配置省电模式------------------- + // 不省电(数据传输会更快) + ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE)); + + //----------------WIFI Scan------------------- + uint16_t number = DEFAULT_SCAN_LIST_SIZE; + wifi_ap_record_t ap_info[DEFAULT_SCAN_LIST_SIZE]; + uint16_t ap_count = 0; + memset(ap_info, 0, sizeof(ap_info)); + // 扫描所有有效的AP 阻塞 + esp_wifi_scan_start(NULL, true); + // 获取上次扫描中找到的AP列表 + ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&number, ap_info)); + // 获取上次扫描中找到的AP数获取上次扫描中找到的AP数 + ESP_ERROR_CHECK(esp_wifi_scan_get_ap_num(&ap_count)); + ESP_LOGI(TAG, "Total APs scanned = %u", ap_count); + for (int i = 0; (i < DEFAULT_SCAN_LIST_SIZE) && (i < ap_count); i++) + { + ESP_LOGI(TAG, "SSID \t\t%s", ap_info[i].ssid); // 名称 + ESP_LOGI(TAG, "RSSI \t\t%d", ap_info[i].rssi); // 信号强度 + print_auth_mode(ap_info[i].authmode); // wifi加密模式 + if (ap_info[i].authmode != WIFI_AUTH_WEP) + { + print_cipher_type(ap_info[i].pairwise_cipher, ap_info[i].group_cipher); + } + ESP_LOGI(TAG, "Channel \t\t%d\n", ap_info[i].primary); // 信道 + } +} diff --git a/code/05.wifi/wifi_sta/.gitignore b/code/05.wifi/wifi_sta/.gitignore new file mode 100644 index 0000000..8da877b --- /dev/null +++ b/code/05.wifi/wifi_sta/.gitignore @@ -0,0 +1,6 @@ +build +*managed_components +dependencies.lock +sdkconfig +sdkconfig.old + diff --git a/code/05.wifi/wifi_sta/CMakeLists.txt b/code/05.wifi/wifi_sta/CMakeLists.txt new file mode 100644 index 0000000..664d458 --- /dev/null +++ b/code/05.wifi/wifi_sta/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(main) diff --git a/code/05.wifi/wifi_sta/main/CMakeLists.txt b/code/05.wifi/wifi_sta/main/CMakeLists.txt new file mode 100644 index 0000000..cf2c455 --- /dev/null +++ b/code/05.wifi/wifi_sta/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") diff --git a/code/05.wifi/wifi_sta/main/main.c b/code/05.wifi/wifi_sta/main/main.c new file mode 100644 index 0000000..187b478 --- /dev/null +++ b/code/05.wifi/wifi_sta/main/main.c @@ -0,0 +1,100 @@ +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/event_groups.h" +#include "esp_wifi.h" +#include "esp_log.h" +#include "esp_event.h" +#include "nvs_flash.h" +#include "esp_mac.h" +#include "esp_netif.h" + + +#define ESP_WIFI_STA_SSID "duruofu_win10" +#define ESP_WIFI_STA_PASSWD "1234567890" + +void WIFI_CallBack(void *event_handler_arg, esp_event_base_t event_base, int32_t event_id, void *event_data) +{ + static uint8_t connect_count = 0; + // WIFI 启动成功 + if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) + { + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_START"); + ESP_ERROR_CHECK(esp_wifi_connect()); + } + // WIFI 连接失败 + if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) + { + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_DISCONNECTED"); + connect_count++; + if (connect_count < 6) + { + vTaskDelay(1000 / portTICK_PERIOD_MS); + ESP_ERROR_CHECK(esp_wifi_connect()); + } + else{ + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_DISCONNECTED 10 times"); + } + } + // WIFI 连接成功(获取到了IP) + if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) + { + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_GOT_IP"); + ip_event_got_ip_t *info = (ip_event_got_ip_t *)event_data; + ESP_LOGI("WIFI_EVENT", "got ip:" IPSTR "", IP2STR(&info->ip_info.ip)); + } +} + +void app_main(void) +{ + //----------------准备阶段------------------- + // Initialize NVS + esp_err_t ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) + { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK(ret); + + //----------------初始化阶段------------------- + ESP_ERROR_CHECK(esp_netif_init()); + + ESP_ERROR_CHECK(esp_event_loop_create_default()); + // 注册事件(wifi启动成功) + ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, WIFI_EVENT_STA_START, WIFI_CallBack, NULL, NULL)); + // 注册事件(wifi连接失败) + ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, WIFI_CallBack, NULL, NULL)); + // 注册事件(wifi连接失败) + ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, WIFI_CallBack, NULL, NULL)); + + // 初始化STA设备 + esp_netif_create_default_wifi_sta(); + + /*Initialize WiFi */ + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + // WIFI_INIT_CONFIG_DEFAULT 是一个默认配置的宏 + + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + + //----------------配置阶段------------------- + // 初始化WIFI设备( 为 WiFi 驱动初始化 WiFi 分配资源,如 WiFi 控制结构、RX/TX 缓冲区、WiFi NVS 结构等,这个 WiFi 也启动 WiFi 任务。必须先调用此API,然后才能调用所有其他WiFi API) + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); + + // STA详细配置 + wifi_config_t sta_config = { + .sta = { + .ssid = ESP_WIFI_STA_SSID, + .password = ESP_WIFI_STA_PASSWD, + .bssid_set = false, + }, + }; + ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &sta_config)); + + //----------------启动阶段------------------- + ESP_ERROR_CHECK(esp_wifi_start()); + + //----------------配置省电模式------------------- + // 不省电(数据传输会更快) + ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE)); +} diff --git a/code/05.wifi/wifi_sta_static_ip/.gitignore b/code/05.wifi/wifi_sta_static_ip/.gitignore new file mode 100644 index 0000000..8da877b --- /dev/null +++ b/code/05.wifi/wifi_sta_static_ip/.gitignore @@ -0,0 +1,6 @@ +build +*managed_components +dependencies.lock +sdkconfig +sdkconfig.old + diff --git a/code/05.wifi/wifi_sta_static_ip/CMakeLists.txt b/code/05.wifi/wifi_sta_static_ip/CMakeLists.txt new file mode 100644 index 0000000..664d458 --- /dev/null +++ b/code/05.wifi/wifi_sta_static_ip/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(main) diff --git a/code/05.wifi/wifi_sta_static_ip/main/CMakeLists.txt b/code/05.wifi/wifi_sta_static_ip/main/CMakeLists.txt new file mode 100644 index 0000000..cf2c455 --- /dev/null +++ b/code/05.wifi/wifi_sta_static_ip/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") diff --git a/code/05.wifi/wifi_sta_static_ip/main/main.c b/code/05.wifi/wifi_sta_static_ip/main/main.c new file mode 100644 index 0000000..01bcaf2 --- /dev/null +++ b/code/05.wifi/wifi_sta_static_ip/main/main.c @@ -0,0 +1,114 @@ +#includ < stdio.h> +#include +#include "freertos/FreeRTOS.h" +#include "freertos/event_groups.h" +#include "esp_wifi.h" +#include "esp_log.h" +#include "esp_event.h" +#include "nvs_flash.h" +#include "esp_mac.h" +#include "esp_netif.h" +#include "lwip/inet.h" + +#define ESP_WIFI_STA_SSID "duruofu_win10" +#define ESP_WIFI_STA_PASSWD "1234567890" + +void WIFI_CallBack(void *event_handler_arg, esp_event_base_t event_base, int32_t event_id, void *event_data) +{ + static uint8_t connect_count = 0; + // WIFI 启动成功 + if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) + { + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_START"); + ESP_ERROR_CHECK(esp_wifi_connect()); + } + // WIFI 连接失败 + if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) + { + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_DISCONNECTED"); + connect_count++; + if (connect_count < 6) + { + vTaskDelay(1000 / portTICK_PERIOD_MS); + ESP_ERROR_CHECK(esp_wifi_connect()); + } + else + { + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_DISCONNECTED 10 times"); + } + } + // WIFI 连接成功(获取到了IP) + if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) + { + ESP_LOGI("WIFI_EVENT", "WIFI_EVENT_STA_GOT_IP"); + ip_event_got_ip_t *info = (ip_event_got_ip_t *)event_data; + ESP_LOGI("WIFI_EVENT", "got ip:" IPSTR "", IP2STR(&info->ip_info.ip)); + } +} + +void app_main(void) +{ + //----------------准备阶段------------------- + // Initialize NVS + esp_err_t ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) + { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK(ret); + + //----------------初始化阶段------------------- + ESP_ERROR_CHECK(esp_netif_init()); + + ESP_ERROR_CHECK(esp_event_loop_create_default()); + // 注册事件(wifi启动成功) + ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, WIFI_EVENT_STA_START, WIFI_CallBack, NULL, NULL)); + // 注册事件(wifi连接失败) + ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, WIFI_CallBack, NULL, NULL)); + // 注册事件(wifi连接失败) + ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, WIFI_CallBack, NULL, NULL)); + + // 初始化STA设备 + esp_netif_t *esp_netif = esp_netif_create_default_wifi_sta(); + + // ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ + //*******************配置静态IP************************* + esp_netif_dhcpc_stop(esp_netif); + esp_netif_ip_info_t ipInfo; + ipInfo.ip.addr = inet_addr("192.168.138.2"); + ipInfo.netmask = inet_addr("255.255.255.0"); + ipInfo.gw = inet_addr("192.168.138.2"); + + esp_netif_set_ip_info(esp_netif, &ipInfo); + esp_netif_dhcpc_start(esp_netif); + //*******************配置静态IP************************* + // ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ + + /*Initialize WiFi */ + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + // WIFI_INIT_CONFIG_DEFAULT 是一个默认配置的宏 + + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + + //----------------配置阶段------------------- + // 设置为STA模式 + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); + + // STA详细配置 + wifi_config_t sta_config = { + .sta = { + .ssid = ESP_WIFI_STA_SSID, + .password = ESP_WIFI_STA_PASSWD, + .bssid_set = false, + }, + }; + ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &sta_config)); + + //----------------启动阶段------------------- + ESP_ERROR_CHECK(esp_wifi_start()); + + //----------------配置省电模式------------------- + // 不省电(数据传输会更快) + ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE)); +} diff --git a/code/07.bluetooth/README.md b/code/07.bluetooth/README.md new file mode 100644 index 0000000..e69de29 diff --git a/code/08.gui/lvgl_spd2010_gui/.gitignore b/code/08.gui/lvgl_spd2010_gui/.gitignore new file mode 100644 index 0000000..8da877b --- /dev/null +++ b/code/08.gui/lvgl_spd2010_gui/.gitignore @@ -0,0 +1,6 @@ +build +*managed_components +dependencies.lock +sdkconfig +sdkconfig.old + diff --git a/code/08.gui/lvgl_spd2010_gui/CMakeLists.txt b/code/08.gui/lvgl_spd2010_gui/CMakeLists.txt new file mode 100644 index 0000000..bdafdcf --- /dev/null +++ b/code/08.gui/lvgl_spd2010_gui/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(lvgl_transplant_spd2010) diff --git a/code/08.gui/lvgl_spd2010_gui/main/CMakeLists.txt b/code/08.gui/lvgl_spd2010_gui/main/CMakeLists.txt new file mode 100644 index 0000000..ef3747e --- /dev/null +++ b/code/08.gui/lvgl_spd2010_gui/main/CMakeLists.txt @@ -0,0 +1,23 @@ +file(GLOB_RECURSE srcs *.c + ui/custom/*.c + ui/generated/*.c + ui/generated/guider_customer_fonts/*.c + ui/generated/guider_fonts/*.c + ui/generated/images/*.c + ) + +set(include_dirs + . + ui/custom + ui/generated + ui/generated/guider_customer_fonts + ui/generated/guider_fonts + ui/generated/images + + ) + +idf_component_register( + SRCS ${srcs} + INCLUDE_DIRS ${include_dirs} + REQUIRES lvgl + ) diff --git a/code/08.gui/lvgl_spd2010_gui/main/idf_component.yml b/code/08.gui/lvgl_spd2010_gui/main/idf_component.yml new file mode 100644 index 0000000..3c0f745 --- /dev/null +++ b/code/08.gui/lvgl_spd2010_gui/main/idf_component.yml @@ -0,0 +1,19 @@ +## IDF Component Manager Manifest File +dependencies: + lvgl/lvgl: "^8.3.6~1" + espressif/esp_lcd_spd2010: "*" + espressif/esp_lcd_touch_spd2010: "^0.0.1" + ## Required IDF version + idf: + version: ">=4.1.0" + # # Put list of dependencies here + # # For components maintained by Espressif: + # component: "~1.0.0" + # # For 3rd party components: + # username/component: ">=1.0.0,<2.0.0" + # username2/component2: + # version: "~1.0.0" + # # For transient dependencies `public` flag can be set. + # # `public` flag doesn't have an effect dependencies of the `main` component. + # # All dependencies of `main` are public by default. + # public: true diff --git a/code/08.gui/lvgl_spd2010_gui/main/main.c b/code/08.gui/lvgl_spd2010_gui/main/main.c new file mode 100644 index 0000000..fb79c33 --- /dev/null +++ b/code/08.gui/lvgl_spd2010_gui/main/main.c @@ -0,0 +1,416 @@ +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "driver/gpio.h" +#include "driver/i2c.h" +#include "driver/spi_master.h" +#include "esp_timer.h" +#include "esp_lcd_panel_io.h" +#include "esp_lcd_panel_vendor.h" +#include "esp_lcd_panel_ops.h" +#include "esp_err.h" +#include "esp_log.h" + +#include "lvgl.h" +#include "lv_demos.h" +#include "esp_lcd_spd2010.h" +#include "esp_lcd_touch_spd2010.h" + +#include "gui_guider.h" +#include "custom.h" + +#define LV_LVGL_H_INCLUDE_SIMPLE 1 + +lv_ui guider_ui; + +static const char *TAG = "main"; +static SemaphoreHandle_t lvgl_mux = NULL; + +// LCD和触摸控制器配置 +#define LCD_HOST SPI2_HOST +#define TOUCH_HOST I2C_NUM_0 + + +// 颜色深度 +#define LCD_BIT_PER_PIXEL (16) + +// 引脚配置 +// ESP Board SPD1020 Panel (QSPI) +// ┌──────────────────────┐ ┌────────────────────┐ +// │ GND ├─────────────►│ GND │ +// │ │ │ │ +// │ 3V3 ├─────────────►│ VCC │ +// │ │ │ │ +// │ CS ├─────────────►│ CS │ +// │ │ │ │ +// │ SCK ├─────────────►│ CLK │ +// │ │ │ │ +// │ D3 ├─────────────►│ IO3 │ +// │ │ │ │ +// │ D2 ├─────────────►│ IO2 │ +// │ │ │ │ +// │ D1 ├─────────────►│ IO1 │ +// │ │ │ │ +// │ D0 ├─────────────►│ IO0 │ +// │ │ │ │ +// │ RST ├─────────────►│ RSTN │ +// │ │ │ │ +// │ (SCL) ├─────────────►│ TP_SCL │ +// │ │ │ │ +// │ (SDA) ├─────────────►│ TP_SDA │ +// │ │ │ │ +// │ (TP_INT) ├─────────────►│ TP_INT │ +// │ │ │ │ +// │ (3V3) ├─────────────►│ TP_RST │ +// │ │ │ │ +// └──────────────────────┘ └────────────────────┘ +#define EXAMPLE_LCD_BK_LIGHT_ON_LEVEL 0 +#define EXAMPLE_LCD_BK_LIGHT_OFF_LEVEL !EXAMPLE_LCD_BK_LIGHT_ON_LEVEL +#define EXAMPLE_PIN_NUM_LCD_CS (GPIO_NUM_9) +#define EXAMPLE_PIN_NUM_LCD_PCLK (GPIO_NUM_10) +#define EXAMPLE_PIN_NUM_LCD_DATA0 (GPIO_NUM_11) +#define EXAMPLE_PIN_NUM_LCD_DATA1 (GPIO_NUM_12) +#define EXAMPLE_PIN_NUM_LCD_DATA2 (GPIO_NUM_13) +#define EXAMPLE_PIN_NUM_LCD_DATA3 (GPIO_NUM_14) +#define EXAMPLE_PIN_NUM_LCD_RST (GPIO_NUM_4) +#define EXAMPLE_PIN_NUM_BK_LIGHT (GPIO_NUM_3) + +// 触摸引脚配置 +#define EXAMPLE_PIN_NUM_TOUCH_SCL (GPIO_NUM_18) +#define EXAMPLE_PIN_NUM_TOUCH_SDA (GPIO_NUM_8) +#define EXAMPLE_PIN_NUM_TOUCH_RST (GPIO_NUM_7) +#define EXAMPLE_PIN_NUM_TOUCH_INT (GPIO_NUM_17) + +esp_lcd_touch_handle_t tp = NULL; + + +// LCD分辨率 +#define EXAMPLE_LCD_H_RES 412 +#define EXAMPLE_LCD_V_RES 412 + +// LVGLtask配置 +#define EXAMPLE_LVGL_TICK_PERIOD_MS 2 +#define EXAMPLE_LVGL_TASK_MAX_DELAY_MS 500 +#define EXAMPLE_LVGL_TASK_MIN_DELAY_MS 1 +#define EXAMPLE_LVGL_TASK_STACK_SIZE (4 * 1024) +#define EXAMPLE_LVGL_TASK_PRIORITY 2 + +static bool example_notify_lvgl_flush_ready(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx) +{ + lv_disp_drv_t *disp_driver = (lv_disp_drv_t *)user_ctx; + lv_disp_flush_ready(disp_driver); + return false; +} + + +static void example_lvgl_flush_cb(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map) +{ + esp_lcd_panel_handle_t panel_handle = (esp_lcd_panel_handle_t) drv->user_data; + const int offsetx1 = area->x1; + const int offsetx2 = area->x2; + const int offsety1 = area->y1; + const int offsety2 = area->y2; + + // copy a buffer's content to a specific area of the display + esp_lcd_panel_draw_bitmap(panel_handle, offsetx1, offsety1, offsetx2 + 1, offsety2 + 1, color_map); +} + +/* Rotate display and touch, when rotated screen in LVGL. Called when driver parameters are updated. */ +static void example_lvgl_update_cb(lv_disp_drv_t *drv) +{ + esp_lcd_panel_handle_t panel_handle = (esp_lcd_panel_handle_t) drv->user_data; + + switch (drv->rotated) { + case LV_DISP_ROT_NONE: + // Rotate LCD display + esp_lcd_panel_swap_xy(panel_handle, false); + esp_lcd_panel_mirror(panel_handle, true, false); + // Rotate LCD touch + esp_lcd_touch_set_mirror_y(tp, false); + esp_lcd_touch_set_mirror_x(tp, false); + break; + case LV_DISP_ROT_90: + // Rotate LCD display + esp_lcd_panel_swap_xy(panel_handle, true); + esp_lcd_panel_mirror(panel_handle, true, true); + // Rotate LCD touch + esp_lcd_touch_set_mirror_y(tp, false); + esp_lcd_touch_set_mirror_x(tp, false); + break; + case LV_DISP_ROT_180: + // Rotate LCD display + esp_lcd_panel_swap_xy(panel_handle, false); + esp_lcd_panel_mirror(panel_handle, false, true); + // Rotate LCD touch + esp_lcd_touch_set_mirror_y(tp, false); + esp_lcd_touch_set_mirror_x(tp, false); + + break; + case LV_DISP_ROT_270: + // Rotate LCD display + esp_lcd_panel_swap_xy(panel_handle, true); + esp_lcd_panel_mirror(panel_handle, false, false); + // Rotate LCD touch + esp_lcd_touch_set_mirror_y(tp, false); + esp_lcd_touch_set_mirror_x(tp, false); + break; + } +} + +void example_lvgl_rounder_cb(struct _lv_disp_drv_t *disp_drv, lv_area_t *area) +{ + uint16_t x1 = area->x1; + uint16_t x2 = area->x2; + // round the start of coordinate down to the nearest 4M number + area->x1 = (x1 >> 2) << 2; + // round the end of coordinate up to the nearest 4N+3 number + area->x2 = ((x2 >> 2) << 2) + 3; +} + + +// 触屏信号量 +static SemaphoreHandle_t touch_mux = NULL; +// lvgl触摸回调函数 +static void example_lvgl_touch_cb(lv_indev_drv_t *drv, lv_indev_data_t *data) +{ + esp_lcd_touch_handle_t tp = (esp_lcd_touch_handle_t)drv->user_data; + assert(tp); + + uint16_t tp_x; + uint16_t tp_y; + uint8_t tp_cnt = 0; + /* Read data from touch controller into memory */ + if (xSemaphoreTake(touch_mux, 0) == pdTRUE) { + esp_lcd_touch_read_data(tp); + } + + /* Read data from touch controller */ + bool tp_pressed = esp_lcd_touch_get_coordinates(tp, &tp_x, &tp_y, NULL, &tp_cnt, 1); + if (tp_pressed && tp_cnt > 0) { + data->point.x = tp_x; + data->point.y = tp_y; + data->state = LV_INDEV_STATE_PRESSED; + ESP_LOGI(TAG, "Touch position: %d,%d", tp_x, tp_y); + } else { + data->state = LV_INDEV_STATE_RELEASED; + } +} + +static void example_touch_isr_cb(esp_lcd_touch_handle_t tp) +{ + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + xSemaphoreGiveFromISR(touch_mux, &xHigherPriorityTaskWoken); + + if (xHigherPriorityTaskWoken) { + portYIELD_FROM_ISR(); + } +} + + +// LVGL任务 +static void example_increase_lvgl_tick(void *arg) +{ + /* Tell LVGL how many milliseconds has elapsed */ + lv_tick_inc(EXAMPLE_LVGL_TICK_PERIOD_MS); +} + +static bool example_lvgl_lock(int timeout_ms) +{ + assert(lvgl_mux && "bsp_display_start must be called first"); + + const TickType_t timeout_ticks = (timeout_ms == -1) ? portMAX_DELAY : pdMS_TO_TICKS(timeout_ms); + return xSemaphoreTake(lvgl_mux, timeout_ticks) == pdTRUE; +} + +static void example_lvgl_unlock(void) +{ + assert(lvgl_mux && "bsp_display_start must be called first"); + xSemaphoreGive(lvgl_mux); +} + + +// LVGL任务 +static void example_lvgl_port_task(void *arg) +{ + ESP_LOGI(TAG, "Starting LVGL task"); + // Initialize ui + setup_ui(&guider_ui); + uint32_t task_delay_ms = EXAMPLE_LVGL_TASK_MAX_DELAY_MS; + while (1) { + ESP_LOGI(TAG, "LVGL task"); + // Lock the mutex due to the LVGL APIs are not thread-safe + if (example_lvgl_lock(-1)) { + task_delay_ms = lv_timer_handler(); + // Release the mutex + example_lvgl_unlock(); + } + if (task_delay_ms > EXAMPLE_LVGL_TASK_MAX_DELAY_MS) { + task_delay_ms = EXAMPLE_LVGL_TASK_MAX_DELAY_MS; + } else if (task_delay_ms < EXAMPLE_LVGL_TASK_MIN_DELAY_MS) { + task_delay_ms = EXAMPLE_LVGL_TASK_MIN_DELAY_MS; + } + vTaskDelay(pdMS_TO_TICKS(task_delay_ms)); + } +} + +void app_main(void) +{ + static lv_disp_draw_buf_t disp_buf; // contains internal graphic buffer(s) called draw buffer(s) + static lv_disp_drv_t disp_drv; // contains callback functions + + // 背光引脚配置 + ESP_LOGI(TAG, "Turn off LCD backlight"); + gpio_config_t bk_gpio_config = { + .mode = GPIO_MODE_OUTPUT, + .pin_bit_mask = 1ULL << EXAMPLE_PIN_NUM_BK_LIGHT + }; + ESP_ERROR_CHECK(gpio_config(&bk_gpio_config)); + + ESP_LOGI(TAG, "Initialize SPI bus"); + const spi_bus_config_t buscfg = SPD2010_PANEL_BUS_QSPI_CONFIG(EXAMPLE_PIN_NUM_LCD_PCLK, + EXAMPLE_PIN_NUM_LCD_DATA0, + EXAMPLE_PIN_NUM_LCD_DATA1, + EXAMPLE_PIN_NUM_LCD_DATA2, + EXAMPLE_PIN_NUM_LCD_DATA3, + EXAMPLE_LCD_H_RES * EXAMPLE_LCD_V_RES * LCD_BIT_PER_PIXEL / 8); + + ESP_ERROR_CHECK(spi_bus_initialize(LCD_HOST, &buscfg, SPI_DMA_CH_AUTO)); + + ESP_LOGI(TAG, "Install panel IO"); + esp_lcd_panel_io_handle_t io_handle = NULL; + const esp_lcd_panel_io_spi_config_t io_config = SPD2010_PANEL_IO_QSPI_CONFIG(EXAMPLE_PIN_NUM_LCD_CS, + example_notify_lvgl_flush_ready, + &disp_drv); + spd2010_vendor_config_t vendor_config = { + .flags = { + .use_qspi_interface = 1, + }, + }; + + // Attach the LCD to the SPI bus + ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)LCD_HOST, &io_config, &io_handle)); + + esp_lcd_panel_handle_t panel_handle = NULL; + const esp_lcd_panel_dev_config_t panel_config = { + .reset_gpio_num = EXAMPLE_PIN_NUM_LCD_RST, + .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB, + .bits_per_pixel = LCD_BIT_PER_PIXEL, + .vendor_config = &vendor_config, + }; + ESP_LOGI(TAG, "Install SPD2010 panel driver"); + ESP_ERROR_CHECK(esp_lcd_new_panel_spd2010(io_handle, &panel_config, &panel_handle)); + + + ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle)); + ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle)); + // user can flush pre-defined pattern to the screen before we turn on the screen or backlight + ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true)); + + // 初始化I2C总线 + touch_mux = xSemaphoreCreateBinary(); + assert(touch_mux); + + ESP_LOGI(TAG, "Initialize I2C bus"); + const i2c_config_t i2c_conf = { + .mode = I2C_MODE_MASTER, + .sda_io_num = EXAMPLE_PIN_NUM_TOUCH_SDA, + .sda_pullup_en = GPIO_PULLUP_ENABLE, + .scl_io_num = EXAMPLE_PIN_NUM_TOUCH_SCL, + .scl_pullup_en = GPIO_PULLUP_ENABLE, + .master.clk_speed = 400 * 1000, + }; + ESP_ERROR_CHECK(i2c_param_config(TOUCH_HOST, &i2c_conf)); + ESP_ERROR_CHECK(i2c_driver_install(TOUCH_HOST, i2c_conf.mode, 0, 0, 0)); + + // 触屏驱动IO句柄 + esp_lcd_panel_io_handle_t tp_io_handle = NULL; + const esp_lcd_panel_io_i2c_config_t tp_io_config = ESP_LCD_TOUCH_IO_I2C_SPD2010_CONFIG(); + + const esp_lcd_touch_config_t tp_cfg = { + .x_max = EXAMPLE_LCD_H_RES, + .y_max = EXAMPLE_LCD_V_RES, + .rst_gpio_num = EXAMPLE_PIN_NUM_TOUCH_RST, + .int_gpio_num = EXAMPLE_PIN_NUM_TOUCH_INT, + .levels = { + .reset = 0, + .interrupt = 0, + }, + .flags = { + .swap_xy = 0, + .mirror_x = 0, + .mirror_y = 0, + }, + .interrupt_callback = example_touch_isr_cb, + }; + + // Attach the TOUCH to the I2C bus + ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t)TOUCH_HOST, &tp_io_config, &tp_io_handle)); + + // 初始化触摸驱动 + ESP_LOGI(TAG, "Initialize touch controller SPD2010"); + ESP_ERROR_CHECK(esp_lcd_touch_new_i2c_spd2010(tp_io_handle, &tp_cfg, &tp)); + + // 打开背光 + ESP_LOGI(TAG, "Turn on LCD backlight"); + gpio_set_level(EXAMPLE_PIN_NUM_BK_LIGHT, EXAMPLE_LCD_BK_LIGHT_ON_LEVEL); + + // 初始化LVGL + ESP_LOGI(TAG, "Initialize LVGL library"); + lv_init(); + // alloc draw buffers used by LVGL + // it's recommended to choose the size of the draw buffer(s) to be at least 1/10 screen sized + lv_color_t *buf1 = heap_caps_malloc(EXAMPLE_LCD_H_RES * 10 * sizeof(lv_color_t), MALLOC_CAP_DMA); + assert(buf1); + lv_color_t *buf2 = heap_caps_malloc(EXAMPLE_LCD_H_RES * 10 * sizeof(lv_color_t), MALLOC_CAP_DMA); + assert(buf2); + // initialize LVGL draw buffers + lv_disp_draw_buf_init(&disp_buf, buf1, buf2, EXAMPLE_LCD_H_RES * 10); + + ESP_LOGI(TAG, "Register display driver to LVGL"); + lv_disp_drv_init(&disp_drv); + disp_drv.hor_res = EXAMPLE_LCD_H_RES; + disp_drv.ver_res = EXAMPLE_LCD_V_RES; + disp_drv.flush_cb = example_lvgl_flush_cb; + disp_drv.rounder_cb = example_lvgl_rounder_cb; + disp_drv.drv_update_cb = example_lvgl_update_cb; + disp_drv.draw_buf = &disp_buf; + disp_drv.user_data = panel_handle; + lv_disp_t *disp = lv_disp_drv_register(&disp_drv); + + ESP_LOGI(TAG, "Install LVGL tick timer"); + // Tick interface for LVGL (using esp_timer to generate 2ms periodic event) + const esp_timer_create_args_t lvgl_tick_timer_args = { + .callback = &example_increase_lvgl_tick, + .name = "lvgl_tick" + }; + esp_timer_handle_t lvgl_tick_timer = NULL; + ESP_ERROR_CHECK(esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer)); + ESP_ERROR_CHECK(esp_timer_start_periodic(lvgl_tick_timer, EXAMPLE_LVGL_TICK_PERIOD_MS * 1000)); + + static lv_indev_drv_t indev_drv; // Input device driver (Touch) + lv_indev_drv_init(&indev_drv); + indev_drv.type = LV_INDEV_TYPE_POINTER; + indev_drv.disp = disp; + indev_drv.read_cb = example_lvgl_touch_cb; + indev_drv.user_data = tp; + + lv_indev_drv_register(&indev_drv); + + + lvgl_mux = xSemaphoreCreateMutex(); + assert(lvgl_mux); + xTaskCreate(example_lvgl_port_task, "LVGL", EXAMPLE_LVGL_TASK_STACK_SIZE, NULL, EXAMPLE_LVGL_TASK_PRIORITY, NULL); + + ESP_LOGI(TAG, "Display LVGL demos"); + // Lock the mutex due to the LVGL APIs are not thread-safe + if (example_lvgl_lock(-1)) { + //lv_demo_widgets(); /* A widgets example */ + //lv_demo_music(); /* A modern, smartphone-like music player demo. */ + // lv_demo_stress(); /* A stress test for LVGL. */ + // lv_demo_benchmark(); /* A demo to measure the performance of LVGL or to compare different settings. */ + + // Release the mutex + example_lvgl_unlock(); + } +} + diff --git a/code/08.gui/lvgl_spd2010_gui/main/ui/custom/custom.c b/code/08.gui/lvgl_spd2010_gui/main/ui/custom/custom.c new file mode 100644 index 0000000..ed3f1d9 --- /dev/null +++ b/code/08.gui/lvgl_spd2010_gui/main/ui/custom/custom.c @@ -0,0 +1,42 @@ +/* +* Copyright 2023 NXP +* NXP Confidential and Proprietary. This software is owned or controlled by NXP and may only be used strictly in +* accordance with the applicable license terms. By expressly accepting such terms or by downloading, installing, +* activating and/or otherwise using the software, you are agreeing that you have read, and that you agree to +* comply with and are bound by, such license terms. If you do not agree to be bound by the applicable license +* terms, then you may not retain, install, activate or otherwise use the software. +*/ + + +/********************* + * INCLUDES + *********************/ +#include +#include "lvgl.h" +#include "custom.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/** + * Create a demo application + */ + +void custom_init(lv_ui *ui) +{ + /* Add your codes here */ +} + diff --git a/code/08.gui/lvgl_spd2010_gui/main/ui/custom/custom.h b/code/08.gui/lvgl_spd2010_gui/main/ui/custom/custom.h new file mode 100644 index 0000000..6339506 --- /dev/null +++ b/code/08.gui/lvgl_spd2010_gui/main/ui/custom/custom.h @@ -0,0 +1,23 @@ +/* +* Copyright 2023 NXP +* NXP Confidential and Proprietary. This software is owned or controlled by NXP and may only be used strictly in +* accordance with the applicable license terms. By expressly accepting such terms or by downloading, installing, +* activating and/or otherwise using the software, you are agreeing that you have read, and that you agree to +* comply with and are bound by, such license terms. If you do not agree to be bound by the applicable license +* terms, then you may not retain, install, activate or otherwise use the software. +*/ + +#ifndef __CUSTOM_H_ +#define __CUSTOM_H_ +#ifdef __cplusplus +extern "C" { +#endif + +#include "gui_guider.h" + +void custom_init(lv_ui *ui); + +#ifdef __cplusplus +} +#endif +#endif /* EVENT_CB_H_ */ diff --git a/code/08.gui/lvgl_spd2010_gui/main/ui/custom/custom.mk b/code/08.gui/lvgl_spd2010_gui/main/ui/custom/custom.mk new file mode 100644 index 0000000..39c992d --- /dev/null +++ b/code/08.gui/lvgl_spd2010_gui/main/ui/custom/custom.mk @@ -0,0 +1,7 @@ + +GEN_CSRCS += $(notdir $(wildcard $(PRJ_DIR)/custom/*.c)) + +DEPPATH += --dep-path $(PRJ_DIR)/custom +VPATH += :$(PRJ_DIR)/custom + +CFLAGS += "-I$(PRJ_DIR)/custom" diff --git a/code/08.gui/lvgl_spd2010_gui/main/ui/custom/lv_conf_ext.h b/code/08.gui/lvgl_spd2010_gui/main/ui/custom/lv_conf_ext.h new file mode 100644 index 0000000..9a1270e --- /dev/null +++ b/code/08.gui/lvgl_spd2010_gui/main/ui/custom/lv_conf_ext.h @@ -0,0 +1,42 @@ +/* +* Copyright 2023 NXP +* NXP Confidential and Proprietary. This software is owned or controlled by NXP and may only be used strictly in +* accordance with the applicable license terms. By expressly accepting such terms or by downloading, installing, +* activating and/or otherwise using the software, you are agreeing that you have read, and that you agree to +* comply with and are bound by, such license terms. If you do not agree to be bound by the applicable license +* terms, then you may not retain, install, activate or otherwise use the software. +*/ + +/* + * lv_conf_ext.h for custom lvconf file. + * Created on: Feb 8, 2023 + * example : + * #undef LV_FONT_FMT_TXT_LARGE + * #define LV_FONT_FMT_TXT_LARGE 1 + */ + +#ifndef LV_CONF_EXT_H +#define LV_CONF_EXT_H + + +/* common code begin */ + + +/* common code end */ + + +#if LV_USE_GUIDER_SIMULATOR +/* code for simulator begin */ + + +/* code for simulator end */ +#else +/* code for board begin */ + + +/* code for board end */ +#endif + + + +#endif /* LV_CONF_EXT_H */ \ No newline at end of file diff --git a/code/08.gui/lvgl_spd2010_gui/main/ui/generated/events_init.c b/code/08.gui/lvgl_spd2010_gui/main/ui/generated/events_init.c new file mode 100644 index 0000000..d489d14 --- /dev/null +++ b/code/08.gui/lvgl_spd2010_gui/main/ui/generated/events_init.c @@ -0,0 +1,19 @@ +/* +* Copyright 2024 NXP +* NXP Confidential and Proprietary. This software is owned or controlled by NXP and may only be used strictly in +* accordance with the applicable license terms. By expressly accepting such terms or by downloading, installing, +* activating and/or otherwise using the software, you are agreeing that you have read, and that you agree to +* comply with and are bound by, such license terms. If you do not agree to be bound by the applicable license +* terms, then you may not retain, install, activate or otherwise use the software. +*/ + +#include "events_init.h" +#include +#include "lvgl.h" + + + +void events_init(lv_ui *ui) +{ + +} diff --git a/code/08.gui/lvgl_spd2010_gui/main/ui/generated/events_init.h b/code/08.gui/lvgl_spd2010_gui/main/ui/generated/events_init.h new file mode 100644 index 0000000..c41097e --- /dev/null +++ b/code/08.gui/lvgl_spd2010_gui/main/ui/generated/events_init.h @@ -0,0 +1,26 @@ +/* +* Copyright 2024 NXP +* NXP Confidential and Proprietary. This software is owned or controlled by NXP and may only be used strictly in +* accordance with the applicable license terms. By expressly accepting such terms or by downloading, installing, +* activating and/or otherwise using the software, you are agreeing that you have read, and that you agree to +* comply with and are bound by, such license terms. If you do not agree to be bound by the applicable license +* terms, then you may not retain, install, activate or otherwise use the software. +*/ + + +#ifndef EVENTS_INIT_H_ +#define EVENTS_INIT_H_ +#ifdef __cplusplus +extern "C" { +#endif + +#include "gui_guider.h" + +void events_init(lv_ui *ui); + +void events_init_screen(lv_ui *ui); + +#ifdef __cplusplus +} +#endif +#endif /* EVENT_CB_H_ */ diff --git a/code/08.gui/lvgl_spd2010_gui/main/ui/generated/generated.mk b/code/08.gui/lvgl_spd2010_gui/main/ui/generated/generated.mk new file mode 100644 index 0000000..9c42df2 --- /dev/null +++ b/code/08.gui/lvgl_spd2010_gui/main/ui/generated/generated.mk @@ -0,0 +1,16 @@ +# images +include $(PRJ_DIR)/generated/images/images.mk + +# GUI Guider fonts +include $(PRJ_DIR)/generated/guider_fonts/guider_fonts.mk + +# GUI Guider customer fonts +include $(PRJ_DIR)/generated/guider_customer_fonts/guider_customer_fonts.mk + + +GEN_CSRCS += $(notdir $(wildcard $(PRJ_DIR)/generated/*.c)) + +DEPPATH += --dep-path $(PRJ_DIR)/generated +VPATH += :$(PRJ_DIR)/generated + +CFLAGS += "-I$(PRJ_DIR)/generated" \ No newline at end of file diff --git a/code/08.gui/lvgl_spd2010_gui/main/ui/generated/gui_guider.c b/code/08.gui/lvgl_spd2010_gui/main/ui/generated/gui_guider.c new file mode 100644 index 0000000..3e981c0 --- /dev/null +++ b/code/08.gui/lvgl_spd2010_gui/main/ui/generated/gui_guider.c @@ -0,0 +1,34 @@ +/* +* Copyright 2024 NXP +* NXP Confidential and Proprietary. This software is owned or controlled by NXP and may only be used strictly in +* accordance with the applicable license terms. By expressly accepting such terms or by downloading, installing, +* activating and/or otherwise using the software, you are agreeing that you have read, and that you agree to +* comply with and are bound by, such license terms. If you do not agree to be bound by the applicable license +* terms, then you may not retain, install, activate or otherwise use the software. +*/ + +#include "lvgl.h" +#include +#include "gui_guider.h" + + +void ui_init_style(lv_style_t * style) +{ + if (style->prop_cnt > 1) + lv_style_reset(style); + else + lv_style_init(style); +} + +void init_scr_del_flag(lv_ui *ui) +{ + + ui->screen_del = true; +} + +void setup_ui(lv_ui *ui) +{ + init_scr_del_flag(ui); + setup_scr_screen(ui); + lv_scr_load(ui->screen); +} diff --git a/code/08.gui/lvgl_spd2010_gui/main/ui/generated/gui_guider.h b/code/08.gui/lvgl_spd2010_gui/main/ui/generated/gui_guider.h new file mode 100644 index 0000000..09af4a6 --- /dev/null +++ b/code/08.gui/lvgl_spd2010_gui/main/ui/generated/gui_guider.h @@ -0,0 +1,42 @@ +/* +* Copyright 2024 NXP +* NXP Confidential and Proprietary. This software is owned or controlled by NXP and may only be used strictly in +* accordance with the applicable license terms. By expressly accepting such terms or by downloading, installing, +* activating and/or otherwise using the software, you are agreeing that you have read, and that you agree to +* comply with and are bound by, such license terms. If you do not agree to be bound by the applicable license +* terms, then you may not retain, install, activate or otherwise use the software. +*/ + +#ifndef GUI_GUIDER_H +#define GUI_GUIDER_H +#ifdef __cplusplus +extern "C" { +#endif + +#include "lvgl.h" + +typedef struct +{ + + lv_obj_t *screen; + bool screen_del; + lv_obj_t *screen_btn_1; + lv_obj_t *screen_btn_1_label; + lv_obj_t *screen_chart_1; +}lv_ui; + +void ui_init_style(lv_style_t * style); +void init_scr_del_flag(lv_ui *ui); +void setup_ui(lv_ui *ui); +extern lv_ui guider_ui; + +void setup_scr_screen(lv_ui *ui); + +LV_FONT_DECLARE(lv_font_montserratMedium_16) +LV_FONT_DECLARE(lv_font_montserratMedium_12) + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/code/08.gui/lvgl_spd2010_gui/main/ui/generated/guider_customer_fonts/guider_customer_fonts.h b/code/08.gui/lvgl_spd2010_gui/main/ui/generated/guider_customer_fonts/guider_customer_fonts.h new file mode 100644 index 0000000..b06d7d4 --- /dev/null +++ b/code/08.gui/lvgl_spd2010_gui/main/ui/generated/guider_customer_fonts/guider_customer_fonts.h @@ -0,0 +1,21 @@ +/* +* Copyright 2023 NXP +* NXP Confidential and Proprietary. This software is owned or controlled by NXP and may only be used strictly in +* accordance with the applicable license terms. By expressly accepting such terms or by downloading, installing, +* activating and/or otherwise using the software, you are agreeing that you have read, and that you agree to +* comply with and are bound by, such license terms. If you do not agree to be bound by the applicable license +* terms, then you may not retain, install, activate or otherwise use the software. +*/ + +#ifndef GUIDER_CUSTOMER_FONTS_H +#define GUIDER_CUSTOMER_FONTS_H +#ifdef __cplusplus +extern "C" { +#endif + +#include "lv_font.h" + +#ifdef __cplusplus +} +#endif +#endif \ No newline at end of file diff --git a/code/08.gui/lvgl_spd2010_gui/main/ui/generated/guider_customer_fonts/guider_customer_fonts.mk b/code/08.gui/lvgl_spd2010_gui/main/ui/generated/guider_customer_fonts/guider_customer_fonts.mk new file mode 100644 index 0000000..0cc6a84 --- /dev/null +++ b/code/08.gui/lvgl_spd2010_gui/main/ui/generated/guider_customer_fonts/guider_customer_fonts.mk @@ -0,0 +1,6 @@ +GEN_CSRCS += $(notdir $(wildcard $(PRJ_DIR)/generated/guider_customer_fonts/*.c)) + +DEPPATH += --dep-path $(PRJ_DIR)/generated/guider_customer_fonts +VPATH += :$(PRJ_DIR)/generated/guider_customer_fonts + +CFLAGS += "-I$(PRJ_DIR)/generated/guider_customer_fonts" \ No newline at end of file diff --git a/code/08.gui/lvgl_spd2010_gui/main/ui/generated/guider_fonts/guider_fonts.mk b/code/08.gui/lvgl_spd2010_gui/main/ui/generated/guider_fonts/guider_fonts.mk new file mode 100644 index 0000000..48804a4 --- /dev/null +++ b/code/08.gui/lvgl_spd2010_gui/main/ui/generated/guider_fonts/guider_fonts.mk @@ -0,0 +1,6 @@ +GEN_CSRCS += $(notdir $(wildcard $(PRJ_DIR)/generated/guider_fonts/*.c)) + +DEPPATH += --dep-path $(PRJ_DIR)/generated/guider_fonts +VPATH += :$(PRJ_DIR)/generated/guider_fonts + +CFLAGS += "-I$(PRJ_DIR)/generated/guider_fonts" \ No newline at end of file diff --git a/code/08.gui/lvgl_spd2010_gui/main/ui/generated/guider_fonts/lv_font_montserratMedium_12.c b/code/08.gui/lvgl_spd2010_gui/main/ui/generated/guider_fonts/lv_font_montserratMedium_12.c new file mode 100644 index 0000000..8ac86e7 --- /dev/null +++ b/code/08.gui/lvgl_spd2010_gui/main/ui/generated/guider_fonts/lv_font_montserratMedium_12.c @@ -0,0 +1,1880 @@ +/* + * Copyright 2024 NXP + * NXP Confidential and Proprietary. This software is owned or controlled by NXP and may only be used strictly in + * accordance with the applicable license terms. By expressly accepting such terms or by downloading, installing, + * activating and/or otherwise using the software, you are agreeing that you have read, and that you agree to + * comply with and are bound by, such license terms. If you do not agree to be bound by the applicable license + * terms, then you may not retain, install, activate or otherwise use the software. + */ +/******************************************************************************* + * Size: 12 px + * Bpp: 4 + * Opts: --user-data-dir=C:\Users\duruofu\AppData\Roaming\gui-guider --app-path=C:\NXP\GUI-Guider-1.6.1-GA\resources\app.asar --no-sandbox --no-zygote --lang=zh-CN --device-scale-factor=1.25 --num-raster-threads=4 --enable-main-frame-before-activation --renderer-client-id=5 --time-ticks-at-unix-epoch=-1717375277958826 --launch-time-ticks=92300759598 --mojo-platform-channel-handle=3020 --field-trial-handle=1732,i,14137332758556215245,7603498977609116181,131072 --disable-features=SpareRendererForSitePerProcess,WinRetrieveSuggestionsOnlyOnDemand /prefetch:1 + ******************************************************************************/ + +#ifdef LV_LVGL_H_INCLUDE_SIMPLE +#include "lvgl.h" +#else +#include "lvgl.h" +#endif + +#ifndef LV_FONT_MONTSERRATMEDIUM_12 +#define LV_FONT_MONTSERRATMEDIUM_12 1 +#endif + +#if LV_FONT_MONTSERRATMEDIUM_12 + +/*----------------- + * BITMAPS + *----------------*/ + +/*Store the image of the glyphs*/ +static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { + /* U+0020 " " */ + + /* U+0021 "!" */ + 0xf, 0x40, 0xf3, 0xf, 0x30, 0xf2, 0xe, 0x20, + 0xd1, 0x3, 0x0, 0x81, 0x1e, 0x30, + + /* U+0022 "\"" */ + 0x3c, 0x1e, 0x3b, 0xe, 0x3b, 0xe, 0x15, 0x7, + + /* U+0023 "#" */ + 0x0, 0x48, 0x3, 0xa0, 0x0, 0x6, 0x60, 0x58, + 0x0, 0x4f, 0xff, 0xff, 0xff, 0x10, 0xa, 0x20, + 0x84, 0x0, 0x0, 0xc1, 0xa, 0x30, 0x0, 0xd, + 0x0, 0xb1, 0x0, 0xaf, 0xff, 0xff, 0xfb, 0x0, + 0x1c, 0x0, 0xd0, 0x0, 0x3, 0xa0, 0x1c, 0x0, + 0x0, + + /* U+0024 "$" */ + 0x0, 0x9, 0x20, 0x0, 0x0, 0x92, 0x0, 0x3, + 0xcf, 0xfb, 0x31, 0xf7, 0xa5, 0x74, 0x4e, 0x9, + 0x20, 0x1, 0xf9, 0xb2, 0x0, 0x2, 0xbf, 0xe8, + 0x0, 0x0, 0x97, 0xda, 0x0, 0x9, 0x24, 0xe5, + 0xb4, 0xa5, 0xba, 0x8, 0xef, 0xfa, 0x10, 0x0, + 0x92, 0x0, 0x0, 0x4, 0x10, 0x0, + + /* U+0025 "%" */ + 0xa, 0xc8, 0x0, 0xc, 0x10, 0x66, 0xa, 0x20, + 0x76, 0x0, 0x83, 0x7, 0x42, 0xc0, 0x0, 0x57, + 0xa, 0x2b, 0x20, 0x0, 0x9, 0xc6, 0x68, 0x5c, + 0x90, 0x0, 0x1, 0xc1, 0xc0, 0x67, 0x0, 0xa, + 0x43, 0x90, 0x2a, 0x0, 0x49, 0x1, 0xb0, 0x47, + 0x0, 0xc1, 0x0, 0x7b, 0xb1, + + /* U+0026 "&" */ + 0x0, 0x9e, 0xd4, 0x0, 0x0, 0x5c, 0x3, 0xd0, + 0x0, 0x4, 0xc0, 0x5c, 0x0, 0x0, 0xc, 0xbd, + 0x20, 0x0, 0x3, 0xde, 0x80, 0x10, 0x1, 0xe3, + 0x1d, 0x78, 0x80, 0x6b, 0x0, 0x1d, 0xf2, 0x4, + 0xf4, 0x13, 0xcf, 0x60, 0x6, 0xdf, 0xd6, 0x2b, + 0x0, 0x0, 0x0, 0x0, 0x0, + + /* U+0027 "'" */ + 0x3c, 0x3b, 0x3b, 0x15, + + /* U+0028 "(" */ + 0xa, 0x71, 0xf1, 0x5c, 0x9, 0x80, 0xb6, 0xc, + 0x40, 0xd4, 0xc, 0x40, 0xb6, 0x9, 0x80, 0x5b, + 0x1, 0xf1, 0xa, 0x70, + + /* U+0029 ")" */ + 0x6b, 0x0, 0xf2, 0xb, 0x60, 0x7a, 0x5, 0xc0, + 0x4d, 0x3, 0xe0, 0x4d, 0x5, 0xc0, 0x7a, 0xb, + 0x60, 0xf1, 0x6b, 0x0, + + /* U+002A "*" */ + 0x0, 0xb0, 0x8, 0x9c, 0xb5, 0xb, 0xf8, 0x8, + 0x7c, 0x95, 0x0, 0xa0, 0x0, + + /* U+002B "+" */ + 0x0, 0xb, 0x0, 0x0, 0x0, 0xf0, 0x0, 0x0, + 0xf, 0x0, 0x2, 0xee, 0xfe, 0xe2, 0x1, 0x1f, + 0x11, 0x0, 0x0, 0xf0, 0x0, + + /* U+002D "-" */ + 0x4f, 0xfd, 0x2, 0x22, + + /* U+002E "." */ + 0x2a, 0x4, 0xd0, + + /* U+002F "/" */ + 0x0, 0x0, 0x34, 0x0, 0x0, 0xb5, 0x0, 0x0, + 0xf0, 0x0, 0x5, 0xb0, 0x0, 0xa, 0x60, 0x0, + 0xe, 0x10, 0x0, 0x4c, 0x0, 0x0, 0x97, 0x0, + 0x0, 0xe2, 0x0, 0x3, 0xd0, 0x0, 0x8, 0x70, + 0x0, 0xd, 0x20, 0x0, 0x2d, 0x0, 0x0, + + /* U+0030 "0" */ + 0x0, 0x9e, 0xe9, 0x0, 0xa, 0xd4, 0x4d, 0xa0, + 0x1f, 0x20, 0x2, 0xf1, 0x5e, 0x0, 0x0, 0xd5, + 0x6c, 0x0, 0x0, 0xc6, 0x5e, 0x0, 0x0, 0xd5, + 0x1f, 0x20, 0x2, 0xf1, 0xa, 0xd4, 0x4d, 0xa0, + 0x0, 0x9e, 0xe9, 0x0, + + /* U+0031 "1" */ + 0xef, 0xf3, 0x22, 0xf3, 0x0, 0xf3, 0x0, 0xf3, + 0x0, 0xf3, 0x0, 0xf3, 0x0, 0xf3, 0x0, 0xf3, + 0x0, 0xf3, + + /* U+0032 "2" */ + 0x19, 0xef, 0xc2, 0x8, 0xb4, 0x3a, 0xe0, 0x0, + 0x0, 0x2f, 0x10, 0x0, 0x5, 0xe0, 0x0, 0x2, + 0xe5, 0x0, 0x1, 0xd7, 0x0, 0x1, 0xd8, 0x0, + 0x1, 0xda, 0x22, 0x21, 0x8f, 0xff, 0xff, 0x70, + + /* U+0033 "3" */ + 0x9f, 0xff, 0xff, 0x1, 0x22, 0x2d, 0x80, 0x0, + 0x9, 0xb0, 0x0, 0x5, 0xf2, 0x0, 0x0, 0x7c, + 0xf8, 0x0, 0x0, 0x2, 0xf2, 0x0, 0x0, 0xe, + 0x4b, 0x94, 0x39, 0xf1, 0x3b, 0xff, 0xc3, 0x0, + + /* U+0034 "4" */ + 0x0, 0x0, 0x9b, 0x0, 0x0, 0x4, 0xe1, 0x0, + 0x0, 0x1e, 0x50, 0x0, 0x0, 0xaa, 0x0, 0x0, + 0x5, 0xe1, 0xd, 0x40, 0x1e, 0x40, 0xd, 0x40, + 0x8f, 0xff, 0xff, 0xfd, 0x12, 0x22, 0x2e, 0x62, + 0x0, 0x0, 0xe, 0x40, + + /* U+0035 "5" */ + 0xc, 0xff, 0xff, 0x0, 0xe5, 0x22, 0x20, 0xf, + 0x10, 0x0, 0x1, 0xff, 0xeb, 0x30, 0x2, 0x23, + 0x9f, 0x10, 0x0, 0x0, 0xd6, 0x0, 0x0, 0xd, + 0x69, 0xb4, 0x38, 0xf1, 0x2a, 0xef, 0xc4, 0x0, + + /* U+0036 "6" */ + 0x0, 0x6d, 0xfd, 0x50, 0x8, 0xd5, 0x23, 0x20, + 0x1f, 0x20, 0x0, 0x0, 0x4d, 0x6d, 0xea, 0x10, + 0x6f, 0xc4, 0x3c, 0xa0, 0x5f, 0x30, 0x2, 0xf0, + 0x2f, 0x20, 0x2, 0xf0, 0xa, 0xc3, 0x2b, 0xa0, + 0x1, 0xaf, 0xfa, 0x10, + + /* U+0037 "7" */ + 0xaf, 0xff, 0xff, 0xba, 0x92, 0x22, 0xd7, 0x76, + 0x0, 0x3f, 0x10, 0x0, 0xa, 0x90, 0x0, 0x1, + 0xf2, 0x0, 0x0, 0x7c, 0x0, 0x0, 0xe, 0x50, + 0x0, 0x5, 0xe0, 0x0, 0x0, 0xc8, 0x0, 0x0, + + /* U+0038 "8" */ + 0x3, 0xcf, 0xea, 0x10, 0xe, 0x81, 0x2c, 0xa0, + 0x2f, 0x10, 0x5, 0xd0, 0xe, 0x70, 0x1b, 0x90, + 0x6, 0xff, 0xff, 0x20, 0x3f, 0x50, 0x18, 0xe0, + 0x6c, 0x0, 0x0, 0xf2, 0x3f, 0x61, 0x29, 0xe0, + 0x5, 0xcf, 0xfb, 0x20, + + /* U+0039 "9" */ + 0x7, 0xef, 0xc3, 0x6, 0xe3, 0x15, 0xe1, 0x98, + 0x0, 0xb, 0x87, 0xd2, 0x3, 0xfb, 0xa, 0xff, + 0xd9, 0xc0, 0x0, 0x10, 0x8b, 0x0, 0x0, 0xd, + 0x70, 0x62, 0x4b, 0xd0, 0x1c, 0xfe, 0xa1, 0x0, + + /* U+003A ":" */ + 0x4e, 0x2, 0xa0, 0x0, 0x0, 0x0, 0x0, 0x2, + 0xa0, 0x4d, 0x0, + + /* U+003B ";" */ + 0x4e, 0x2, 0xa0, 0x0, 0x0, 0x0, 0x0, 0x1, + 0x80, 0x4f, 0x10, 0xd0, 0x38, 0x0, + + /* U+003C "<" */ + 0x0, 0x0, 0x2, 0x10, 0x0, 0x4b, 0xe1, 0x7, + 0xdc, 0x50, 0x3, 0xf8, 0x0, 0x0, 0x4, 0xbe, + 0x71, 0x0, 0x0, 0x29, 0xe2, 0x0, 0x0, 0x0, + 0x0, + + /* U+003D "=" */ + 0x3f, 0xff, 0xff, 0x30, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x2, 0xee, 0xee, 0xe2, 0x1, 0x11, + 0x11, 0x0, + + /* U+003E ">" */ + 0x12, 0x0, 0x0, 0x2, 0xeb, 0x40, 0x0, 0x0, + 0x5c, 0xd6, 0x0, 0x0, 0x8, 0xf2, 0x1, 0x7e, + 0xb4, 0x2, 0xe9, 0x20, 0x0, 0x0, 0x0, 0x0, + 0x0, + + /* U+003F "?" */ + 0x1a, 0xef, 0xc3, 0x9, 0xa3, 0x2a, 0xe0, 0x0, + 0x0, 0x3f, 0x0, 0x0, 0xa, 0xa0, 0x0, 0x9, + 0xc0, 0x0, 0x2, 0xf1, 0x0, 0x0, 0x1, 0x0, + 0x0, 0x2, 0x80, 0x0, 0x0, 0x4d, 0x0, 0x0, + + /* U+0040 "@" */ + 0x0, 0x4, 0xbd, 0xdd, 0x81, 0x0, 0x0, 0x9b, + 0x30, 0x0, 0x6d, 0x30, 0x7, 0xa0, 0x8e, 0xe8, + 0xd5, 0xd1, 0xd, 0x7, 0xd2, 0x19, 0xf3, 0x77, + 0x4a, 0xd, 0x40, 0x0, 0xf3, 0x1b, 0x58, 0xf, + 0x20, 0x0, 0xd3, 0xc, 0x58, 0xd, 0x40, 0x0, + 0xf3, 0x1b, 0x3a, 0x7, 0xd2, 0x1a, 0xf5, 0x77, + 0xd, 0x0, 0x8e, 0xe8, 0x5f, 0xb0, 0x6, 0xa0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x9b, 0x30, 0x2, + 0x40, 0x0, 0x0, 0x5, 0xbd, 0xed, 0x60, 0x0, + + /* U+0041 "A" */ + 0x0, 0x0, 0x6f, 0x30, 0x0, 0x0, 0x0, 0xdd, + 0x90, 0x0, 0x0, 0x4, 0xe3, 0xf1, 0x0, 0x0, + 0xb, 0x80, 0xc7, 0x0, 0x0, 0x1f, 0x20, 0x6e, + 0x0, 0x0, 0x8c, 0x0, 0x1f, 0x50, 0x0, 0xef, + 0xee, 0xef, 0xb0, 0x6, 0xe2, 0x11, 0x14, 0xf2, + 0xc, 0x70, 0x0, 0x0, 0xb9, + + /* U+0042 "B" */ + 0xbf, 0xff, 0xfb, 0x20, 0xb7, 0x11, 0x2a, 0xd0, + 0xb7, 0x0, 0x3, 0xf0, 0xb7, 0x0, 0x8, 0xc0, + 0xbf, 0xff, 0xff, 0x50, 0xb8, 0x22, 0x26, 0xf2, + 0xb7, 0x0, 0x0, 0xc7, 0xb7, 0x11, 0x15, 0xf4, + 0xbf, 0xff, 0xfd, 0x60, + + /* U+0043 "C" */ + 0x0, 0x3b, 0xef, 0xb3, 0x0, 0x5f, 0x93, 0x38, + 0xe0, 0xe, 0x60, 0x0, 0x0, 0x4, 0xe0, 0x0, + 0x0, 0x0, 0x6c, 0x0, 0x0, 0x0, 0x4, 0xe0, + 0x0, 0x0, 0x0, 0xe, 0x60, 0x0, 0x0, 0x0, + 0x5f, 0x93, 0x38, 0xe0, 0x0, 0x3b, 0xff, 0xb3, + 0x0, + + /* U+0044 "D" */ + 0xbf, 0xff, 0xea, 0x30, 0xb, 0x82, 0x23, 0x9f, + 0x40, 0xb7, 0x0, 0x0, 0x7e, 0xb, 0x70, 0x0, + 0x0, 0xf3, 0xb7, 0x0, 0x0, 0xe, 0x5b, 0x70, + 0x0, 0x0, 0xf3, 0xb7, 0x0, 0x0, 0x7e, 0xb, + 0x82, 0x23, 0x9f, 0x40, 0xbf, 0xff, 0xeb, 0x30, + 0x0, + + /* U+0045 "E" */ + 0xbf, 0xff, 0xff, 0x3b, 0x82, 0x22, 0x20, 0xb7, + 0x0, 0x0, 0xb, 0x70, 0x0, 0x0, 0xbf, 0xff, + 0xfa, 0xb, 0x82, 0x22, 0x10, 0xb7, 0x0, 0x0, + 0xb, 0x82, 0x22, 0x20, 0xbf, 0xff, 0xff, 0x50, + + /* U+0046 "F" */ + 0xbf, 0xff, 0xff, 0x3b, 0x82, 0x22, 0x20, 0xb7, + 0x0, 0x0, 0xb, 0x70, 0x0, 0x0, 0xbf, 0xff, + 0xfa, 0xb, 0x82, 0x22, 0x10, 0xb7, 0x0, 0x0, + 0xb, 0x70, 0x0, 0x0, 0xb7, 0x0, 0x0, 0x0, + + /* U+0047 "G" */ + 0x0, 0x3b, 0xef, 0xc4, 0x0, 0x5f, 0x94, 0x38, + 0xe1, 0xe, 0x70, 0x0, 0x0, 0x4, 0xe0, 0x0, + 0x0, 0x0, 0x6c, 0x0, 0x0, 0x8, 0x24, 0xe0, + 0x0, 0x0, 0xe3, 0xe, 0x60, 0x0, 0xe, 0x30, + 0x5f, 0x93, 0x37, 0xf3, 0x0, 0x3b, 0xef, 0xc4, + 0x0, + + /* U+0048 "H" */ + 0xb7, 0x0, 0x0, 0xb7, 0xb7, 0x0, 0x0, 0xb7, + 0xb7, 0x0, 0x0, 0xb7, 0xb7, 0x0, 0x0, 0xb7, + 0xbf, 0xff, 0xff, 0xf7, 0xb8, 0x22, 0x22, 0xc7, + 0xb7, 0x0, 0x0, 0xb7, 0xb7, 0x0, 0x0, 0xb7, + 0xb7, 0x0, 0x0, 0xb7, + + /* U+0049 "I" */ + 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, + 0xb7, + + /* U+004A "J" */ + 0x4, 0xff, 0xff, 0x0, 0x22, 0x5f, 0x0, 0x0, + 0x3f, 0x0, 0x0, 0x3f, 0x0, 0x0, 0x3f, 0x0, + 0x0, 0x3f, 0x0, 0x0, 0x4e, 0xd, 0x52, 0xba, + 0x5, 0xdf, 0xb2, + + /* U+004B "K" */ + 0xb7, 0x0, 0x7, 0xd1, 0xb7, 0x0, 0x5e, 0x20, + 0xb7, 0x4, 0xe3, 0x0, 0xb7, 0x3e, 0x40, 0x0, + 0xb9, 0xef, 0x20, 0x0, 0xbf, 0x89, 0xd0, 0x0, + 0xba, 0x0, 0xca, 0x0, 0xb7, 0x0, 0x1e, 0x70, + 0xb7, 0x0, 0x3, 0xf3, + + /* U+004C "L" */ + 0xb7, 0x0, 0x0, 0xb, 0x70, 0x0, 0x0, 0xb7, + 0x0, 0x0, 0xb, 0x70, 0x0, 0x0, 0xb7, 0x0, + 0x0, 0xb, 0x70, 0x0, 0x0, 0xb7, 0x0, 0x0, + 0xb, 0x82, 0x22, 0x20, 0xbf, 0xff, 0xff, 0x0, + + /* U+004D "M" */ + 0xb8, 0x0, 0x0, 0x1, 0xf3, 0xbf, 0x10, 0x0, + 0x9, 0xf3, 0xbe, 0xa0, 0x0, 0x2e, 0xf3, 0xb7, + 0xe3, 0x0, 0xb7, 0xf3, 0xb6, 0x7b, 0x4, 0xd0, + 0xf3, 0xb6, 0xd, 0x4c, 0x50, 0xf3, 0xb6, 0x5, + 0xfc, 0x0, 0xf3, 0xb6, 0x0, 0xb3, 0x0, 0xf3, + 0xb6, 0x0, 0x0, 0x0, 0xf3, + + /* U+004E "N" */ + 0xb9, 0x0, 0x0, 0xb7, 0xbf, 0x50, 0x0, 0xb7, + 0xbc, 0xf2, 0x0, 0xb7, 0xb7, 0xad, 0x0, 0xb7, + 0xb7, 0xd, 0x90, 0xb7, 0xb7, 0x2, 0xf5, 0xb7, + 0xb7, 0x0, 0x6f, 0xd7, 0xb7, 0x0, 0xa, 0xf7, + 0xb7, 0x0, 0x0, 0xd7, + + /* U+004F "O" */ + 0x0, 0x3b, 0xef, 0xb4, 0x0, 0x5, 0xf9, 0x33, + 0x8f, 0x60, 0xe, 0x60, 0x0, 0x5, 0xf1, 0x4e, + 0x0, 0x0, 0x0, 0xd5, 0x6c, 0x0, 0x0, 0x0, + 0xb7, 0x4e, 0x0, 0x0, 0x0, 0xd5, 0xe, 0x60, + 0x0, 0x5, 0xf1, 0x5, 0xf9, 0x33, 0x8f, 0x60, + 0x0, 0x3b, 0xef, 0xb4, 0x0, + + /* U+0050 "P" */ + 0xbf, 0xff, 0xd8, 0x0, 0xb8, 0x22, 0x5d, 0x90, + 0xb7, 0x0, 0x4, 0xe0, 0xb7, 0x0, 0x3, 0xf0, + 0xb7, 0x0, 0x2c, 0xa0, 0xbf, 0xff, 0xfa, 0x10, + 0xb8, 0x22, 0x0, 0x0, 0xb7, 0x0, 0x0, 0x0, + 0xb7, 0x0, 0x0, 0x0, + + /* U+0051 "Q" */ + 0x0, 0x3b, 0xef, 0xb4, 0x0, 0x4, 0xf9, 0x33, + 0x8f, 0x60, 0xe, 0x60, 0x0, 0x5, 0xf1, 0x4e, + 0x0, 0x0, 0x0, 0xd5, 0x6c, 0x0, 0x0, 0x0, + 0xb7, 0x4e, 0x0, 0x0, 0x0, 0xd6, 0xf, 0x60, + 0x0, 0x5, 0xf1, 0x5, 0xf8, 0x32, 0x7f, 0x60, + 0x0, 0x4c, 0xff, 0xc5, 0x0, 0x0, 0x0, 0xc, + 0xb0, 0x28, 0x0, 0x0, 0x1, 0xbf, 0xe5, 0x0, + 0x0, 0x0, 0x0, 0x0, + + /* U+0052 "R" */ + 0xbf, 0xff, 0xd8, 0x0, 0xb8, 0x22, 0x5d, 0x90, + 0xb7, 0x0, 0x4, 0xe0, 0xb7, 0x0, 0x3, 0xf0, + 0xb7, 0x0, 0x1b, 0xb0, 0xbf, 0xff, 0xfb, 0x10, + 0xb8, 0x22, 0xb9, 0x0, 0xb7, 0x0, 0x1f, 0x30, + 0xb7, 0x0, 0x7, 0xd0, + + /* U+0053 "S" */ + 0x3, 0xcf, 0xeb, 0x31, 0xf7, 0x23, 0x74, 0x4e, + 0x0, 0x0, 0x1, 0xf9, 0x20, 0x0, 0x2, 0xbf, + 0xd7, 0x0, 0x0, 0x4, 0xca, 0x0, 0x0, 0x4, + 0xe5, 0xb4, 0x23, 0xbb, 0x8, 0xdf, 0xea, 0x10, + + /* U+0054 "T" */ + 0xff, 0xff, 0xff, 0xf2, 0x23, 0xf3, 0x22, 0x0, + 0x1f, 0x10, 0x0, 0x1, 0xf1, 0x0, 0x0, 0x1f, + 0x10, 0x0, 0x1, 0xf1, 0x0, 0x0, 0x1f, 0x10, + 0x0, 0x1, 0xf1, 0x0, 0x0, 0x1f, 0x10, 0x0, + + /* U+0055 "U" */ + 0xd6, 0x0, 0x0, 0xe4, 0xd6, 0x0, 0x0, 0xe4, + 0xd6, 0x0, 0x0, 0xe4, 0xd6, 0x0, 0x0, 0xe4, + 0xd6, 0x0, 0x0, 0xe4, 0xc7, 0x0, 0x0, 0xf3, + 0x9a, 0x0, 0x2, 0xf1, 0x2f, 0x83, 0x5d, 0xa0, + 0x4, 0xcf, 0xd8, 0x0, + + /* U+0056 "V" */ + 0xc, 0x70, 0x0, 0x0, 0xd5, 0x6, 0xe0, 0x0, + 0x4, 0xe0, 0x0, 0xf4, 0x0, 0xa, 0x80, 0x0, + 0x9b, 0x0, 0x1f, 0x20, 0x0, 0x2f, 0x20, 0x7b, + 0x0, 0x0, 0xc, 0x80, 0xe4, 0x0, 0x0, 0x5, + 0xe5, 0xe0, 0x0, 0x0, 0x0, 0xee, 0x70, 0x0, + 0x0, 0x0, 0x8f, 0x10, 0x0, + + /* U+0057 "W" */ + 0x7c, 0x0, 0x0, 0xe8, 0x0, 0x2, 0xf0, 0x2f, + 0x10, 0x3, 0xfd, 0x0, 0x7, 0xa0, 0xd, 0x60, + 0x8, 0x9f, 0x20, 0xc, 0x50, 0x8, 0xb0, 0xe, + 0x3b, 0x70, 0x1f, 0x0, 0x3, 0xf0, 0x3e, 0x6, + 0xc0, 0x6b, 0x0, 0x0, 0xe5, 0x89, 0x1, 0xf1, + 0xb6, 0x0, 0x0, 0x9a, 0xd4, 0x0, 0xb7, 0xf1, + 0x0, 0x0, 0x4f, 0xe0, 0x0, 0x6f, 0xc0, 0x0, + 0x0, 0xf, 0xa0, 0x0, 0x1f, 0x70, 0x0, + + /* U+0058 "X" */ + 0x5f, 0x10, 0x0, 0xe5, 0xa, 0xb0, 0x9, 0xa0, + 0x1, 0xe6, 0x4e, 0x10, 0x0, 0x4f, 0xe4, 0x0, + 0x0, 0xd, 0xe0, 0x0, 0x0, 0x7d, 0xd8, 0x0, + 0x2, 0xf3, 0x2f, 0x30, 0xc, 0x80, 0x7, 0xd0, + 0x8d, 0x0, 0x0, 0xc9, + + /* U+0059 "Y" */ + 0xc, 0x80, 0x0, 0xa, 0x80, 0x3f, 0x10, 0x3, + 0xe0, 0x0, 0xaa, 0x0, 0xc6, 0x0, 0x1, 0xf3, + 0x5d, 0x0, 0x0, 0x7, 0xce, 0x40, 0x0, 0x0, + 0xe, 0xb0, 0x0, 0x0, 0x0, 0xb7, 0x0, 0x0, + 0x0, 0xb, 0x70, 0x0, 0x0, 0x0, 0xb7, 0x0, + 0x0, + + /* U+005A "Z" */ + 0x6f, 0xff, 0xff, 0xf5, 0x2, 0x22, 0x29, 0xd0, + 0x0, 0x0, 0x3f, 0x30, 0x0, 0x1, 0xe6, 0x0, + 0x0, 0xb, 0xa0, 0x0, 0x0, 0x8d, 0x0, 0x0, + 0x4, 0xf2, 0x0, 0x0, 0x1e, 0x82, 0x22, 0x21, + 0x7f, 0xff, 0xff, 0xf8, + + /* U+005B "[" */ + 0xbf, 0xcb, 0x60, 0xb6, 0xb, 0x60, 0xb6, 0xb, + 0x60, 0xb6, 0xb, 0x60, 0xb6, 0xb, 0x60, 0xb6, + 0xb, 0x60, 0xbf, 0xc0, + + /* U+005C "\\" */ + 0x35, 0x0, 0x0, 0x2e, 0x0, 0x0, 0xd, 0x30, + 0x0, 0x8, 0x80, 0x0, 0x3, 0xd0, 0x0, 0x0, + 0xd2, 0x0, 0x0, 0x87, 0x0, 0x0, 0x3c, 0x0, + 0x0, 0xe, 0x10, 0x0, 0x9, 0x70, 0x0, 0x4, + 0xc0, 0x0, 0x0, 0xe1, 0x0, 0x0, 0xa6, + + /* U+005D "]" */ + 0xcf, 0xb0, 0x7b, 0x6, 0xb0, 0x6b, 0x6, 0xb0, + 0x6b, 0x6, 0xb0, 0x6b, 0x6, 0xb0, 0x6b, 0x6, + 0xb0, 0x7b, 0xcf, 0xb0, + + /* U+005E "^" */ + 0x0, 0x7, 0x0, 0x0, 0x5, 0xe5, 0x0, 0x0, + 0xb4, 0xb0, 0x0, 0x2c, 0xc, 0x20, 0x8, 0x60, + 0x68, 0x0, 0xd0, 0x0, 0xd0, + + /* U+005F "_" */ + 0xdd, 0xdd, 0xdd, + + /* U+0060 "`" */ + 0x27, 0x10, 0x5, 0xc1, + + /* U+0061 "a" */ + 0x8, 0xdf, 0xc3, 0x0, 0xa4, 0x29, 0xd0, 0x0, + 0x0, 0x1f, 0x10, 0x8d, 0xee, 0xf2, 0x4e, 0x10, + 0xf, 0x24, 0xe0, 0x7, 0xf2, 0x9, 0xed, 0x8f, + 0x20, + + /* U+0062 "b" */ + 0xe4, 0x0, 0x0, 0xe, 0x40, 0x0, 0x0, 0xe4, + 0x0, 0x0, 0xe, 0x7c, 0xfc, 0x40, 0xef, 0x52, + 0x8f, 0x2e, 0x60, 0x0, 0xb8, 0xe4, 0x0, 0x8, + 0xae, 0x60, 0x0, 0xb8, 0xef, 0x52, 0x8f, 0x2e, + 0x6d, 0xfc, 0x40, + + /* U+0063 "c" */ + 0x2, 0xbf, 0xe8, 0x0, 0xda, 0x24, 0xc3, 0x5d, + 0x0, 0x0, 0x7, 0xb0, 0x0, 0x0, 0x5d, 0x0, + 0x0, 0x0, 0xda, 0x24, 0xd3, 0x2, 0xbf, 0xe8, + 0x0, + + /* U+0064 "d" */ + 0x0, 0x0, 0x1, 0xf1, 0x0, 0x0, 0x1, 0xf1, + 0x0, 0x0, 0x1, 0xf1, 0x2, 0xbf, 0xd6, 0xf1, + 0xe, 0x92, 0x3d, 0xf1, 0x5d, 0x0, 0x4, 0xf1, + 0x7b, 0x0, 0x1, 0xf1, 0x5d, 0x0, 0x3, 0xf1, + 0xe, 0x91, 0x2d, 0xf1, 0x2, 0xbf, 0xe6, 0xf1, + + /* U+0065 "e" */ + 0x2, 0xbf, 0xd5, 0x0, 0xe8, 0x14, 0xe4, 0x5c, + 0x0, 0x6, 0xb7, 0xfe, 0xee, 0xec, 0x5d, 0x0, + 0x0, 0x0, 0xe9, 0x23, 0xa2, 0x2, 0xbf, 0xe9, + 0x0, + + /* U+0066 "f" */ + 0x1, 0xcf, 0x60, 0x9a, 0x11, 0xb, 0x60, 0xd, + 0xff, 0xf3, 0xb, 0x60, 0x0, 0xb6, 0x0, 0xb, + 0x60, 0x0, 0xb6, 0x0, 0xb, 0x60, 0x0, 0xb6, + 0x0, + + /* U+0067 "g" */ + 0x2, 0xbf, 0xe6, 0xe2, 0xe, 0xa2, 0x3c, 0xf2, + 0x5d, 0x0, 0x2, 0xf2, 0x7b, 0x0, 0x0, 0xf2, + 0x5d, 0x0, 0x2, 0xf2, 0xe, 0xa2, 0x3d, 0xf2, + 0x2, 0xbf, 0xe5, 0xf2, 0x0, 0x0, 0x2, 0xf0, + 0xc, 0x62, 0x3b, 0xa0, 0x6, 0xdf, 0xea, 0x10, + + /* U+0068 "h" */ + 0xe4, 0x0, 0x0, 0xe, 0x40, 0x0, 0x0, 0xe4, + 0x0, 0x0, 0xe, 0x7d, 0xfc, 0x20, 0xee, 0x42, + 0xac, 0xe, 0x60, 0x2, 0xf0, 0xe4, 0x0, 0xf, + 0x1e, 0x40, 0x0, 0xf2, 0xe4, 0x0, 0xf, 0x2e, + 0x40, 0x0, 0xf2, + + /* U+0069 "i" */ + 0xd, 0x40, 0x82, 0x0, 0x0, 0xe4, 0xe, 0x40, + 0xe4, 0xe, 0x40, 0xe4, 0xe, 0x40, 0xe4, + + /* U+006A "j" */ + 0x0, 0xd, 0x50, 0x0, 0x72, 0x0, 0x0, 0x0, + 0x0, 0xd4, 0x0, 0xd, 0x40, 0x0, 0xd4, 0x0, + 0xd, 0x40, 0x0, 0xd4, 0x0, 0xd, 0x40, 0x0, + 0xd4, 0x0, 0xd, 0x40, 0x22, 0xf2, 0xd, 0xf8, + 0x0, + + /* U+006B "k" */ + 0xe4, 0x0, 0x0, 0xe, 0x40, 0x0, 0x0, 0xe4, + 0x0, 0x0, 0xe, 0x40, 0xb, 0xa0, 0xe4, 0xb, + 0xb0, 0xe, 0x4b, 0xc0, 0x0, 0xee, 0xfd, 0x0, + 0xe, 0xc1, 0xd9, 0x0, 0xe4, 0x2, 0xf4, 0xe, + 0x40, 0x6, 0xe1, + + /* U+006C "l" */ + 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, + 0xe4, 0xe4, + + /* U+006D "m" */ + 0xe7, 0xdf, 0xb2, 0x9e, 0xe8, 0xe, 0xd3, 0x2c, + 0xfb, 0x23, 0xe5, 0xe6, 0x0, 0x4f, 0x10, 0x9, + 0x9e, 0x40, 0x3, 0xf0, 0x0, 0x8a, 0xe4, 0x0, + 0x3f, 0x0, 0x8, 0xae, 0x40, 0x3, 0xf0, 0x0, + 0x8a, 0xe4, 0x0, 0x3f, 0x0, 0x8, 0xa0, + + /* U+006E "n" */ + 0xe6, 0xdf, 0xc2, 0xe, 0xe4, 0x1a, 0xc0, 0xe6, + 0x0, 0x1f, 0xe, 0x40, 0x0, 0xf1, 0xe4, 0x0, + 0xf, 0x2e, 0x40, 0x0, 0xf2, 0xe4, 0x0, 0xf, + 0x20, + + /* U+006F "o" */ + 0x2, 0xbf, 0xe8, 0x0, 0xe, 0xa2, 0x3e, 0x80, + 0x5d, 0x0, 0x4, 0xf0, 0x7b, 0x0, 0x1, 0xf1, + 0x5d, 0x0, 0x4, 0xf0, 0xd, 0xa2, 0x3e, 0x80, + 0x2, 0xbf, 0xe8, 0x0, + + /* U+0070 "p" */ + 0xe7, 0xdf, 0xc4, 0xe, 0xf4, 0x16, 0xf2, 0xe6, + 0x0, 0xa, 0x8e, 0x40, 0x0, 0x8a, 0xe7, 0x0, + 0xb, 0x8e, 0xf5, 0x28, 0xf2, 0xe6, 0xcf, 0xc4, + 0xe, 0x40, 0x0, 0x0, 0xe4, 0x0, 0x0, 0xe, + 0x40, 0x0, 0x0, + + /* U+0071 "q" */ + 0x2, 0xbf, 0xd5, 0xf1, 0xe, 0xa2, 0x3e, 0xf1, + 0x5d, 0x0, 0x4, 0xf1, 0x7b, 0x0, 0x1, 0xf1, + 0x5d, 0x0, 0x4, 0xf1, 0xe, 0xa2, 0x3e, 0xf1, + 0x2, 0xbf, 0xd5, 0xf1, 0x0, 0x0, 0x1, 0xf1, + 0x0, 0x0, 0x1, 0xf1, 0x0, 0x0, 0x1, 0xf1, + + /* U+0072 "r" */ + 0xe6, 0xd8, 0xee, 0x61, 0xe7, 0x0, 0xe4, 0x0, + 0xe4, 0x0, 0xe4, 0x0, 0xe4, 0x0, + + /* U+0073 "s" */ + 0x9, 0xef, 0xc2, 0x6d, 0x22, 0x61, 0x7d, 0x20, + 0x0, 0x9, 0xfe, 0x91, 0x0, 0x2, 0xc9, 0x56, + 0x22, 0xb8, 0x4c, 0xfe, 0xa0, + + /* U+0074 "t" */ + 0x5, 0x30, 0x0, 0xb6, 0x0, 0xdf, 0xff, 0x30, + 0xb6, 0x0, 0xb, 0x60, 0x0, 0xb6, 0x0, 0xb, + 0x60, 0x0, 0xaa, 0x11, 0x2, 0xdf, 0x60, + + /* U+0075 "u" */ + 0xf3, 0x0, 0x2f, 0xf, 0x30, 0x2, 0xf0, 0xf3, + 0x0, 0x2f, 0xf, 0x30, 0x2, 0xf0, 0xe4, 0x0, + 0x4f, 0xa, 0xb2, 0x2c, 0xf0, 0x1b, 0xfe, 0x6f, + 0x0, + + /* U+0076 "v" */ + 0xd, 0x50, 0x0, 0x98, 0x6, 0xc0, 0x0, 0xf2, + 0x1, 0xf2, 0x6, 0xb0, 0x0, 0xa8, 0xc, 0x50, + 0x0, 0x3e, 0x3e, 0x0, 0x0, 0xd, 0xd8, 0x0, + 0x0, 0x6, 0xf2, 0x0, + + /* U+0077 "w" */ + 0xc5, 0x0, 0x3f, 0x10, 0x7, 0x86, 0xa0, 0x9, + 0xf6, 0x0, 0xd3, 0x1f, 0x0, 0xe7, 0xb0, 0x2d, + 0x0, 0xb5, 0x4c, 0xe, 0x18, 0x80, 0x6, 0xa9, + 0x60, 0xa6, 0xd3, 0x0, 0x1f, 0xe1, 0x4, 0xed, + 0x0, 0x0, 0xbb, 0x0, 0xe, 0x80, 0x0, + + /* U+0078 "x" */ + 0x5d, 0x0, 0x4e, 0x10, 0xa9, 0x1e, 0x40, 0x1, + 0xed, 0x90, 0x0, 0x8, 0xf1, 0x0, 0x2, 0xeb, + 0xa0, 0x0, 0xc7, 0xd, 0x60, 0x7c, 0x0, 0x3f, + 0x20, + + /* U+0079 "y" */ + 0xd, 0x50, 0x0, 0x98, 0x7, 0xb0, 0x0, 0xe2, + 0x1, 0xf2, 0x5, 0xc0, 0x0, 0xa7, 0xb, 0x50, + 0x0, 0x4d, 0x1e, 0x0, 0x0, 0xe, 0xb9, 0x0, + 0x0, 0x8, 0xf3, 0x0, 0x0, 0x5, 0xd0, 0x0, + 0x5, 0x2c, 0x60, 0x0, 0x1c, 0xf9, 0x0, 0x0, + + /* U+007A "z" */ + 0x7f, 0xff, 0xfb, 0x0, 0x2, 0xf3, 0x0, 0xc, + 0x70, 0x0, 0x9b, 0x0, 0x4, 0xe1, 0x0, 0x1e, + 0x50, 0x0, 0x8f, 0xff, 0xfd, + + /* U+007B "{" */ + 0x0, 0xbf, 0x4, 0xe1, 0x5, 0xc0, 0x5, 0xc0, + 0x5, 0xc0, 0x6, 0xc0, 0x4f, 0x60, 0x8, 0xc0, + 0x5, 0xc0, 0x5, 0xc0, 0x5, 0xc0, 0x4, 0xe1, + 0x0, 0xbf, + + /* U+007C "|" */ + 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, + + /* U+007D "}" */ + 0xcd, 0x10, 0xc, 0x70, 0x9, 0x90, 0x9, 0x90, + 0x9, 0x90, 0x8, 0xa0, 0x3, 0xf7, 0x8, 0xb0, + 0x9, 0x90, 0x9, 0x90, 0x9, 0x90, 0xc, 0x80, + 0xcd, 0x20, + + /* U+007E "~" */ + 0xb, 0xe8, 0xa, 0x33, 0x91, 0x8d, 0xa0, + + /* U+F001 "" */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x12, 0x0, 0x0, + 0x0, 0x3, 0x7c, 0xff, 0x0, 0x0, 0x59, 0xef, + 0xff, 0xff, 0x0, 0xe, 0xff, 0xff, 0xff, 0xff, + 0x0, 0xf, 0xff, 0xfd, 0x84, 0x8f, 0x0, 0xf, + 0xd7, 0x20, 0x0, 0x8f, 0x0, 0xf, 0x80, 0x0, + 0x0, 0x8f, 0x0, 0xf, 0x80, 0x0, 0x0, 0x8f, + 0x0, 0xf, 0x80, 0x0, 0x7b, 0xdf, 0x2, 0x3f, + 0x80, 0x6, 0xff, 0xff, 0xaf, 0xff, 0x80, 0x2, + 0xef, 0xf9, 0xef, 0xff, 0x60, 0x0, 0x2, 0x10, + 0x29, 0xa7, 0x0, 0x0, 0x0, 0x0, + + /* U+F008 "" */ + 0xb4, 0xdf, 0xff, 0xff, 0xfd, 0x4b, 0xe8, 0xe7, + 0x22, 0x22, 0x7e, 0x8e, 0xc0, 0xc5, 0x0, 0x0, + 0x6c, 0xc, 0xfc, 0xf6, 0x11, 0x11, 0x7f, 0xcf, + 0xc0, 0xcf, 0xff, 0xff, 0xfb, 0xc, 0xfc, 0xf6, + 0x11, 0x11, 0x7f, 0xcf, 0xc0, 0xc5, 0x0, 0x0, + 0x6c, 0xc, 0xe8, 0xe7, 0x22, 0x22, 0x7e, 0x8e, + 0xb4, 0xdf, 0xff, 0xff, 0xfd, 0x4b, + + /* U+F00B "" */ + 0xdf, 0xf6, 0x9f, 0xff, 0xff, 0xfd, 0xff, 0xf8, + 0xcf, 0xff, 0xff, 0xff, 0xef, 0xf6, 0xaf, 0xff, + 0xff, 0xfe, 0x13, 0x20, 0x3, 0x33, 0x33, 0x31, + 0xff, 0xf7, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xf8, + 0xcf, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xbf, 0xff, + 0xff, 0xff, 0x13, 0x20, 0x3, 0x33, 0x33, 0x31, + 0xef, 0xf6, 0xaf, 0xff, 0xff, 0xfe, 0xff, 0xf8, + 0xcf, 0xff, 0xff, 0xff, 0xdf, 0xf6, 0xaf, 0xff, + 0xff, 0xfd, + + /* U+F00C "" */ + 0x0, 0x0, 0x0, 0x0, 0x3, 0xd4, 0x0, 0x0, + 0x0, 0x0, 0x3f, 0xfe, 0x0, 0x0, 0x0, 0x3, + 0xff, 0xf4, 0x4d, 0x30, 0x0, 0x3f, 0xff, 0x40, + 0xef, 0xf3, 0x3, 0xff, 0xf4, 0x0, 0x4f, 0xff, + 0x6f, 0xff, 0x40, 0x0, 0x4, 0xff, 0xff, 0xf4, + 0x0, 0x0, 0x0, 0x4f, 0xff, 0x40, 0x0, 0x0, + 0x0, 0x3, 0xd3, 0x0, 0x0, 0x0, + + /* U+F00D "" */ + 0x14, 0x0, 0x0, 0x22, 0xd, 0xf7, 0x0, 0x4f, + 0xf1, 0x9f, 0xf7, 0x4f, 0xfd, 0x0, 0xaf, 0xff, + 0xfd, 0x10, 0x0, 0xbf, 0xfe, 0x10, 0x0, 0x4f, + 0xff, 0xf7, 0x0, 0x4f, 0xfd, 0xaf, 0xf7, 0xe, + 0xfd, 0x10, 0xaf, 0xf2, 0x5b, 0x10, 0x0, 0x99, + 0x0, + + /* U+F011 "" */ + 0x0, 0x0, 0x7, 0x70, 0x0, 0x0, 0x0, 0x32, + 0xf, 0xf0, 0x24, 0x0, 0x5, 0xfc, 0xf, 0xf0, + 0xcf, 0x50, 0x1f, 0xf4, 0xf, 0xf0, 0x5f, 0xf1, + 0x7f, 0x80, 0xf, 0xf0, 0x8, 0xf7, 0xbf, 0x20, + 0xf, 0xf0, 0x2, 0xfb, 0xcf, 0x10, 0xe, 0xe0, + 0x1, 0xfc, 0xaf, 0x40, 0x1, 0x10, 0x4, 0xfa, + 0x5f, 0xb0, 0x0, 0x0, 0xb, 0xf6, 0xd, 0xfa, + 0x10, 0x1, 0xaf, 0xd0, 0x2, 0xdf, 0xfc, 0xcf, + 0xfd, 0x20, 0x0, 0x8, 0xef, 0xfe, 0x91, 0x0, + 0x0, 0x0, 0x1, 0x10, 0x0, 0x0, + + /* U+F013 "" */ + 0x0, 0x0, 0x14, 0x41, 0x0, 0x0, 0x0, 0x0, + 0x7f, 0xf7, 0x0, 0x0, 0x3, 0x43, 0xdf, 0xfd, + 0x34, 0x30, 0xe, 0xff, 0xff, 0xff, 0xff, 0xe0, + 0x6f, 0xff, 0xfb, 0xbf, 0xff, 0xf6, 0x1b, 0xff, + 0x70, 0x7, 0xff, 0xb1, 0x7, 0xff, 0x20, 0x2, + 0xff, 0x70, 0x1b, 0xff, 0x70, 0x7, 0xff, 0xb1, + 0x6f, 0xff, 0xfb, 0xbf, 0xff, 0xf6, 0xe, 0xff, + 0xff, 0xff, 0xff, 0xe0, 0x3, 0x42, 0xcf, 0xfc, + 0x23, 0x30, 0x0, 0x0, 0x7f, 0xf7, 0x0, 0x0, + 0x0, 0x0, 0x4, 0x41, 0x0, 0x0, + + /* U+F015 "" */ + 0x0, 0x0, 0x0, 0x73, 0x3, 0x83, 0x0, 0x0, + 0x0, 0x1d, 0xff, 0x67, 0xf7, 0x0, 0x0, 0x3, + 0xee, 0x5a, 0xfe, 0xf7, 0x0, 0x0, 0x6f, 0xd3, + 0xb5, 0x7f, 0xf7, 0x0, 0x9, 0xfb, 0x3d, 0xff, + 0x85, 0xfe, 0x30, 0xbf, 0x95, 0xff, 0xff, 0xfb, + 0x3e, 0xf4, 0x76, 0x6f, 0xff, 0xff, 0xff, 0xd2, + 0xa1, 0x0, 0xcf, 0xff, 0xff, 0xff, 0xf4, 0x0, + 0x0, 0xcf, 0xfa, 0x2, 0xff, 0xf4, 0x0, 0x0, + 0xcf, 0xfa, 0x2, 0xff, 0xf4, 0x0, 0x0, 0xaf, + 0xf8, 0x1, 0xff, 0xf3, 0x0, + + /* U+F019 "" */ + 0x0, 0x0, 0x27, 0x72, 0x0, 0x0, 0x0, 0x0, + 0x7f, 0xf7, 0x0, 0x0, 0x0, 0x0, 0x8f, 0xf8, + 0x0, 0x0, 0x0, 0x0, 0x8f, 0xf8, 0x0, 0x0, + 0x0, 0x0, 0x8f, 0xf8, 0x0, 0x0, 0x0, 0xdf, + 0xff, 0xff, 0xfd, 0x0, 0x0, 0x4f, 0xff, 0xff, + 0xf4, 0x0, 0x0, 0x4, 0xff, 0xff, 0x40, 0x0, + 0x23, 0x33, 0x5f, 0xf5, 0x33, 0x32, 0xff, 0xff, + 0xa4, 0x4a, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xcf, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5c, 0x8f, + 0x9a, 0xaa, 0xaa, 0xaa, 0xaa, 0xa8, + + /* U+F01C "" */ + 0x0, 0x4f, 0xff, 0xff, 0xff, 0xb0, 0x0, 0x1, + 0xed, 0x88, 0x88, 0x89, 0xf8, 0x0, 0xa, 0xf2, + 0x0, 0x0, 0x0, 0xaf, 0x30, 0x5f, 0x70, 0x0, + 0x0, 0x0, 0x1e, 0xc0, 0xef, 0x88, 0x60, 0x0, + 0x28, 0x8b, 0xf6, 0xff, 0xff, 0xf3, 0x0, 0xbf, + 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, + 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf4, + + /* U+F021 "" */ + 0x0, 0x0, 0x1, 0x10, 0x0, 0x59, 0x0, 0x19, + 0xef, 0xfd, 0x70, 0x9f, 0x3, 0xef, 0xda, 0x9d, + 0xfe, 0xbf, 0xe, 0xf6, 0x0, 0x0, 0x5f, 0xff, + 0x7f, 0x70, 0x0, 0x3f, 0xff, 0xff, 0x69, 0x0, + 0x0, 0x2a, 0xaa, 0xa9, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xaa, 0xaa, 0xa2, 0x0, 0x0, 0xa6, + 0xff, 0xfe, 0xf3, 0x0, 0x7, 0xf7, 0xff, 0xf5, + 0x0, 0x0, 0x7f, 0xe0, 0xfb, 0xef, 0xd9, 0xad, + 0xfe, 0x30, 0xfa, 0x8, 0xef, 0xfe, 0x91, 0x0, + 0x95, 0x0, 0x1, 0x10, 0x0, 0x0, + + /* U+F026 "" */ + 0x0, 0x0, 0x2a, 0x0, 0x2, 0xef, 0x78, 0x8e, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xdf, 0xff, 0xff, 0x0, 0x7, 0xff, + 0x0, 0x0, 0x7f, 0x0, 0x0, 0x1, + + /* U+F027 "" */ + 0x0, 0x0, 0x2a, 0x0, 0x0, 0x0, 0x2e, 0xf0, + 0x0, 0x78, 0x8e, 0xff, 0x3, 0xf, 0xff, 0xff, + 0xf0, 0xba, 0xff, 0xff, 0xff, 0x3, 0xff, 0xff, + 0xff, 0xf0, 0xaa, 0xdf, 0xff, 0xff, 0x4, 0x0, + 0x0, 0x8f, 0xf0, 0x0, 0x0, 0x0, 0x8f, 0x0, + 0x0, 0x0, 0x0, 0x10, 0x0, + + /* U+F028 "" */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x6, 0xd2, 0x0, 0x0, 0x0, + 0x2a, 0x0, 0x11, 0x8e, 0x10, 0x0, 0x2, 0xef, + 0x0, 0x7d, 0x2b, 0x90, 0x78, 0x8e, 0xff, 0x3, + 0xa, 0xb3, 0xf0, 0xff, 0xff, 0xff, 0xb, 0xa1, + 0xf1, 0xe3, 0xff, 0xff, 0xff, 0x3, 0xf0, 0xe3, + 0xc5, 0xff, 0xff, 0xff, 0xb, 0xa1, 0xf1, 0xe3, + 0xdf, 0xff, 0xff, 0x3, 0xa, 0xb3, 0xf0, 0x0, + 0x7, 0xff, 0x0, 0x7d, 0x2b, 0x90, 0x0, 0x0, + 0x7f, 0x0, 0x11, 0x9e, 0x10, 0x0, 0x0, 0x1, + 0x0, 0x6, 0xd2, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, + + /* U+F03E "" */ + 0xbf, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xfd, 0x5b, + 0xff, 0xff, 0xff, 0xff, 0xf5, 0x1, 0xff, 0xff, + 0xef, 0xff, 0xfb, 0x18, 0xff, 0xf6, 0x1c, 0xff, + 0xff, 0xfc, 0xff, 0x60, 0x1, 0xdf, 0xff, 0x60, + 0x96, 0x0, 0x0, 0x8f, 0xf9, 0x0, 0x0, 0x0, + 0x0, 0x8f, 0xfc, 0x88, 0x88, 0x88, 0x88, 0xcf, + 0xbf, 0xff, 0xff, 0xff, 0xff, 0xfb, + + /* U+F048 "" */ + 0x58, 0x0, 0x0, 0x35, 0x9f, 0x10, 0x5, 0xfe, + 0x9f, 0x10, 0x6f, 0xfe, 0x9f, 0x17, 0xff, 0xfe, + 0x9f, 0x9f, 0xff, 0xfe, 0x9f, 0xff, 0xff, 0xfe, + 0x9f, 0xef, 0xff, 0xfe, 0x9f, 0x2d, 0xff, 0xfe, + 0x9f, 0x10, 0xcf, 0xfe, 0x9f, 0x10, 0xb, 0xfe, + 0x8f, 0x0, 0x0, 0x9b, 0x0, 0x0, 0x0, 0x0, + + /* U+F04B "" */ + 0x46, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, 0x40, + 0x0, 0x0, 0x0, 0xff, 0xff, 0xa1, 0x0, 0x0, + 0xf, 0xff, 0xff, 0xf7, 0x0, 0x0, 0xff, 0xff, + 0xff, 0xfd, 0x50, 0xf, 0xff, 0xff, 0xff, 0xff, + 0xb1, 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0xff, + 0xff, 0xff, 0xff, 0xb1, 0xff, 0xff, 0xff, 0xfd, + 0x40, 0xf, 0xff, 0xff, 0xf7, 0x0, 0x0, 0xff, + 0xff, 0xa1, 0x0, 0x0, 0xf, 0xfd, 0x40, 0x0, + 0x0, 0x0, 0x36, 0x0, 0x0, 0x0, 0x0, 0x0, + + /* U+F04C "" */ + 0xaf, 0xfe, 0x30, 0xaf, 0xfe, 0x3f, 0xff, 0xf7, + 0xf, 0xff, 0xf7, 0xff, 0xff, 0x80, 0xff, 0xff, + 0x8f, 0xff, 0xf8, 0xf, 0xff, 0xf8, 0xff, 0xff, + 0x80, 0xff, 0xff, 0x8f, 0xff, 0xf8, 0xf, 0xff, + 0xf8, 0xff, 0xff, 0x80, 0xff, 0xff, 0x8f, 0xff, + 0xf8, 0xf, 0xff, 0xf8, 0xff, 0xff, 0x80, 0xff, + 0xff, 0x8f, 0xff, 0xf7, 0xf, 0xff, 0xf7, 0x48, + 0x98, 0x10, 0x48, 0x98, 0x10, + + /* U+F04D "" */ + 0x48, 0x88, 0x88, 0x88, 0x88, 0x1f, 0xff, 0xff, + 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x8f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x8f, 0xff, 0xff, 0xff, 0xff, + 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8f, 0xff, + 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xaf, + 0xff, 0xff, 0xff, 0xfe, 0x30, + + /* U+F051 "" */ + 0x26, 0x0, 0x0, 0x58, 0x7f, 0xa0, 0x0, 0xbf, + 0x8f, 0xfb, 0x0, 0xbf, 0x8f, 0xff, 0xc1, 0xbf, + 0x8f, 0xff, 0xfd, 0xcf, 0x8f, 0xff, 0xff, 0xff, + 0x8f, 0xff, 0xff, 0xef, 0x8f, 0xff, 0xf4, 0xbf, + 0x8f, 0xff, 0x40, 0xbf, 0x8f, 0xe3, 0x0, 0xbf, + 0x5d, 0x20, 0x0, 0xae, 0x0, 0x0, 0x0, 0x0, + + /* U+F052 "" */ + 0x0, 0x0, 0x3, 0x70, 0x0, 0x0, 0x0, 0x0, + 0x3f, 0xfa, 0x0, 0x0, 0x0, 0x2, 0xef, 0xff, + 0x90, 0x0, 0x0, 0x1e, 0xff, 0xff, 0xf8, 0x0, + 0x1, 0xdf, 0xff, 0xff, 0xff, 0x70, 0xc, 0xff, + 0xff, 0xff, 0xff, 0xf4, 0xd, 0xff, 0xff, 0xff, + 0xff, 0xf5, 0x1, 0x34, 0x44, 0x44, 0x44, 0x30, + 0xd, 0xff, 0xff, 0xff, 0xff, 0xf5, 0xf, 0xff, + 0xff, 0xff, 0xff, 0xf8, 0xc, 0xff, 0xff, 0xff, + 0xff, 0xf5, + + /* U+F053 "" */ + 0x0, 0x0, 0x3, 0x10, 0x0, 0x5, 0xfb, 0x0, + 0x5, 0xff, 0x40, 0x5, 0xff, 0x40, 0x5, 0xff, + 0x50, 0x3, 0xff, 0x50, 0x0, 0xb, 0xfc, 0x10, + 0x0, 0xb, 0xfc, 0x10, 0x0, 0xc, 0xfc, 0x10, + 0x0, 0xc, 0xfb, 0x0, 0x0, 0xa, 0x50, + + /* U+F054 "" */ + 0x3, 0x10, 0x0, 0x3, 0xfc, 0x10, 0x0, 0xb, + 0xfc, 0x10, 0x0, 0xb, 0xfc, 0x10, 0x0, 0xb, + 0xfc, 0x10, 0x0, 0xd, 0xfb, 0x0, 0x5, 0xff, + 0x50, 0x5, 0xff, 0x50, 0x5, 0xff, 0x50, 0x3, + 0xff, 0x50, 0x0, 0xa, 0x50, 0x0, 0x0, + + /* U+F067 "" */ + 0x0, 0x0, 0x69, 0x10, 0x0, 0x0, 0x0, 0xd, + 0xf5, 0x0, 0x0, 0x0, 0x0, 0xef, 0x60, 0x0, + 0x0, 0x0, 0xe, 0xf6, 0x0, 0x0, 0x58, 0x88, + 0xff, 0xb8, 0x88, 0x1f, 0xff, 0xff, 0xff, 0xff, + 0xf7, 0x9b, 0xbb, 0xff, 0xdb, 0xbb, 0x30, 0x0, + 0xe, 0xf6, 0x0, 0x0, 0x0, 0x0, 0xef, 0x60, + 0x0, 0x0, 0x0, 0xe, 0xf6, 0x0, 0x0, 0x0, + 0x0, 0x9d, 0x20, 0x0, 0x0, + + /* U+F068 "" */ + 0x46, 0x66, 0x66, 0x66, 0x66, 0x1f, 0xff, 0xff, + 0xff, 0xff, 0xf7, 0xad, 0xdd, 0xdd, 0xdd, 0xdd, + 0x40, + + /* U+F06E "" */ + 0x0, 0x3, 0xad, 0xff, 0xc7, 0x0, 0x0, 0x0, + 0x9f, 0xe6, 0x24, 0xaf, 0xe3, 0x0, 0xb, 0xff, + 0x20, 0x77, 0x9, 0xff, 0x40, 0x7f, 0xf9, 0x0, + 0xcf, 0xa1, 0xff, 0xe1, 0xef, 0xf6, 0x7f, 0xff, + 0xf0, 0xef, 0xf7, 0x8f, 0xf9, 0x3f, 0xff, 0xc1, + 0xff, 0xe1, 0xb, 0xff, 0x26, 0xca, 0x19, 0xff, + 0x40, 0x0, 0x9f, 0xe6, 0x24, 0xaf, 0xe3, 0x0, + 0x0, 0x3, 0x9d, 0xff, 0xc7, 0x0, 0x0, + + /* U+F070 "" */ + 0x32, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xdf, 0x50, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x1c, 0xf8, 0x4a, 0xef, 0xeb, 0x50, 0x0, 0x0, + 0x0, 0x9f, 0xfd, 0x52, 0x5d, 0xfc, 0x10, 0x0, + 0x0, 0x5, 0xfe, 0x4a, 0x70, 0xcf, 0xe1, 0x0, + 0xb, 0x80, 0x2d, 0xff, 0xf7, 0x4f, 0xfb, 0x0, + 0x2f, 0xfb, 0x0, 0xaf, 0xfb, 0x2f, 0xff, 0x30, + 0xb, 0xff, 0x50, 0x7, 0xfe, 0x7f, 0xfb, 0x0, + 0x1, 0xdf, 0xc0, 0x0, 0x3e, 0xff, 0xe1, 0x0, + 0x0, 0x1b, 0xfc, 0x42, 0x1, 0xbf, 0xa0, 0x0, + 0x0, 0x0, 0x5b, 0xef, 0xb0, 0x8, 0xfc, 0x10, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4f, 0xe0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x40, + + /* U+F071 "" */ + 0x0, 0x0, 0x0, 0x3, 0x10, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x5, 0xfd, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xef, 0xf7, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x8f, 0xff, 0xf1, 0x0, 0x0, 0x0, 0x0, + 0x2f, 0xfd, 0xef, 0xa0, 0x0, 0x0, 0x0, 0xb, + 0xfb, 0x3, 0xff, 0x30, 0x0, 0x0, 0x4, 0xff, + 0xc0, 0x4f, 0xfc, 0x0, 0x0, 0x0, 0xdf, 0xfd, + 0x5, 0xff, 0xf6, 0x0, 0x0, 0x7f, 0xff, 0xf8, + 0xcf, 0xff, 0xe1, 0x0, 0x1f, 0xff, 0xfc, 0x4, + 0xff, 0xff, 0x90, 0xa, 0xff, 0xff, 0xd2, 0x7f, + 0xff, 0xff, 0x20, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xf6, 0x4, 0x78, 0x88, 0x88, 0x88, 0x88, + 0x87, 0x0, + + /* U+F074 "" */ + 0x0, 0x0, 0x0, 0x0, 0x6, 0x10, 0x0, 0x0, + 0x0, 0x0, 0xf, 0xc1, 0xff, 0xf8, 0x0, 0x2e, + 0xff, 0xfc, 0xcd, 0xff, 0x62, 0xef, 0xdf, 0xf9, + 0x0, 0x2c, 0x4e, 0xf9, 0xf, 0x90, 0x0, 0x2, + 0xef, 0x90, 0x7, 0x0, 0x0, 0x2e, 0xf8, 0x88, + 0xf, 0xa0, 0xcd, 0xff, 0x80, 0xdf, 0xdf, 0xf9, + 0xff, 0xf8, 0x0, 0x1e, 0xff, 0xfc, 0x0, 0x0, + 0x0, 0x0, 0xf, 0xc0, 0x0, 0x0, 0x0, 0x0, + 0x6, 0x10, + + /* U+F077 "" */ + 0x0, 0x0, 0x27, 0x0, 0x0, 0x0, 0x0, 0x2e, + 0xf9, 0x0, 0x0, 0x0, 0x2e, 0xff, 0xf9, 0x0, + 0x0, 0x2e, 0xf9, 0x2e, 0xf9, 0x0, 0x2e, 0xf9, + 0x0, 0x2e, 0xf9, 0xb, 0xf9, 0x0, 0x0, 0x2e, + 0xf4, 0x27, 0x0, 0x0, 0x0, 0x27, 0x0, + + /* U+F078 "" */ + 0x27, 0x0, 0x0, 0x0, 0x27, 0xb, 0xf9, 0x0, + 0x0, 0x2e, 0xf4, 0x2e, 0xf9, 0x0, 0x2e, 0xf9, + 0x0, 0x2e, 0xf9, 0x2e, 0xf9, 0x0, 0x0, 0x2e, + 0xff, 0xf9, 0x0, 0x0, 0x0, 0x2e, 0xf9, 0x0, + 0x0, 0x0, 0x0, 0x26, 0x0, 0x0, 0x0, + + /* U+F079 "" */ + 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x3f, 0xc0, 0x7, 0x77, 0x77, 0x72, 0x0, + 0x3, 0xff, 0xfc, 0x2e, 0xff, 0xff, 0xf9, 0x0, + 0xf, 0xcf, 0xcf, 0xa0, 0x0, 0x0, 0xe9, 0x0, + 0x4, 0x1e, 0x93, 0x20, 0x0, 0x0, 0xe9, 0x0, + 0x0, 0xe, 0x90, 0x0, 0x0, 0x0, 0xe9, 0x0, + 0x0, 0xe, 0x90, 0x0, 0x0, 0xb5, 0xe9, 0x97, + 0x0, 0xe, 0xc7, 0x77, 0x73, 0xbf, 0xff, 0xf6, + 0x0, 0xd, 0xff, 0xff, 0xfd, 0xb, 0xff, 0x70, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa6, 0x0, + + /* U+F07B "" */ + 0xbf, 0xff, 0xf6, 0x0, 0x0, 0x0, 0xff, 0xff, + 0xff, 0x98, 0x88, 0x74, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xbf, 0xff, 0xff, 0xff, 0xff, 0xfb, + + /* U+F093 "" */ + 0x0, 0x0, 0x2, 0x20, 0x0, 0x0, 0x0, 0x0, + 0x3e, 0xe3, 0x0, 0x0, 0x0, 0x3, 0xef, 0xfe, + 0x30, 0x0, 0x0, 0x3e, 0xff, 0xff, 0xe3, 0x0, + 0x0, 0xef, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, + 0x8f, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x8f, 0xf8, + 0x0, 0x0, 0x0, 0x0, 0x8f, 0xf8, 0x0, 0x0, + 0x23, 0x32, 0x8f, 0xf8, 0x23, 0x32, 0xff, 0xfe, + 0x39, 0x93, 0xef, 0xff, 0xff, 0xff, 0xc9, 0x9c, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5c, 0x8f, + 0x9a, 0xaa, 0xaa, 0xaa, 0xaa, 0xa8, + + /* U+F095 "" */ + 0x0, 0x0, 0x0, 0x0, 0x3, 0x62, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xcf, 0xfe, 0x0, 0x0, 0x0, + 0x0, 0x3f, 0xff, 0xe0, 0x0, 0x0, 0x0, 0x9, + 0xff, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x2d, 0xff, + 0x90, 0x0, 0x0, 0x0, 0x0, 0x4f, 0xf4, 0x0, + 0x0, 0x0, 0x0, 0xc, 0xfd, 0x0, 0x0, 0x1, + 0x0, 0x9, 0xff, 0x40, 0x1, 0x8e, 0xe1, 0x1a, + 0xff, 0x70, 0x0, 0xef, 0xff, 0xde, 0xff, 0x90, + 0x0, 0xc, 0xff, 0xff, 0xff, 0x60, 0x0, 0x0, + 0x8f, 0xff, 0xe9, 0x10, 0x0, 0x0, 0x2, 0x76, + 0x30, 0x0, 0x0, 0x0, 0x0, + + /* U+F0C4 "" */ + 0x7, 0x93, 0x0, 0x0, 0x22, 0xa, 0xff, 0xf2, + 0x0, 0x8f, 0xf5, 0xf9, 0x1f, 0x70, 0x8f, 0xf9, + 0xc, 0xfc, 0xf8, 0x8f, 0xf9, 0x0, 0x1a, 0xef, + 0xff, 0xf9, 0x0, 0x0, 0x0, 0xef, 0xfc, 0x0, + 0x0, 0x7, 0xbf, 0xff, 0xf6, 0x0, 0xa, 0xff, + 0xfa, 0xbf, 0xf6, 0x0, 0xf9, 0x1f, 0x70, 0xbf, + 0xf6, 0xc, 0xfc, 0xf4, 0x0, 0xbf, 0xf4, 0x1a, + 0xc6, 0x0, 0x0, 0x56, 0x0, + + /* U+F0C5 "" */ + 0x0, 0x3, 0x44, 0x41, 0x20, 0x0, 0x0, 0xff, + 0xff, 0x5e, 0x40, 0x24, 0x1f, 0xff, 0xf5, 0xee, + 0x2f, 0xf4, 0xff, 0xff, 0xc8, 0x82, 0xff, 0x4f, + 0xff, 0xff, 0xff, 0x5f, 0xf4, 0xff, 0xff, 0xff, + 0xf5, 0xff, 0x4f, 0xff, 0xff, 0xff, 0x5f, 0xf4, + 0xff, 0xff, 0xff, 0xf5, 0xff, 0x4f, 0xff, 0xff, + 0xff, 0x5f, 0xf4, 0xff, 0xff, 0xff, 0xf4, 0xff, + 0x93, 0x44, 0x44, 0x43, 0xf, 0xff, 0xff, 0xff, + 0x50, 0x0, 0x68, 0x88, 0x88, 0x71, 0x0, 0x0, + + /* U+F0C7 "" */ + 0x48, 0x88, 0x88, 0x87, 0x0, 0xf, 0xff, 0xff, + 0xff, 0xfb, 0x0, 0xf8, 0x0, 0x0, 0xb, 0xfb, + 0xf, 0x80, 0x0, 0x0, 0xbf, 0xf3, 0xfb, 0x77, + 0x77, 0x7d, 0xff, 0x4f, 0xff, 0xff, 0xff, 0xff, + 0xf4, 0xff, 0xff, 0x42, 0xdf, 0xff, 0x4f, 0xff, + 0xc0, 0x8, 0xff, 0xf4, 0xff, 0xfe, 0x0, 0xaf, + 0xff, 0x4f, 0xff, 0xfc, 0xaf, 0xff, 0xf4, 0xaf, + 0xff, 0xff, 0xff, 0xfd, 0x10, + + /* U+F0E7 "" */ + 0x1, 0xbb, 0xba, 0x10, 0x0, 0x5f, 0xff, 0xf1, + 0x0, 0x7, 0xff, 0xfb, 0x0, 0x0, 0x9f, 0xff, + 0x60, 0x0, 0xb, 0xff, 0xff, 0xff, 0x60, 0xef, + 0xff, 0xff, 0xf1, 0xe, 0xff, 0xff, 0xf8, 0x0, + 0x0, 0xc, 0xfe, 0x0, 0x0, 0x0, 0xff, 0x50, + 0x0, 0x0, 0x3f, 0xc0, 0x0, 0x0, 0x7, 0xf3, + 0x0, 0x0, 0x0, 0xa9, 0x0, 0x0, 0x0, 0x2, + 0x0, 0x0, 0x0, + + /* U+F0EA "" */ + 0x0, 0x2a, 0x50, 0x0, 0x0, 0xe, 0xff, 0x8f, + 0xff, 0x20, 0x0, 0xff, 0xf8, 0xff, 0xf4, 0x0, + 0xf, 0xff, 0xeb, 0xbb, 0x30, 0x0, 0xff, 0xf4, + 0x99, 0x92, 0x60, 0xf, 0xff, 0x5f, 0xff, 0x4f, + 0xa0, 0xff, 0xf5, 0xff, 0xf5, 0x56, 0x1f, 0xff, + 0x5f, 0xff, 0xff, 0xf4, 0xff, 0xf5, 0xff, 0xff, + 0xff, 0x4e, 0xff, 0x5f, 0xff, 0xff, 0xf4, 0x0, + 0x5, 0xff, 0xff, 0xff, 0x40, 0x0, 0x5f, 0xff, + 0xff, 0xf4, 0x0, 0x0, 0x44, 0x44, 0x44, 0x0, + + /* U+F0F3 "" */ + 0x0, 0x0, 0x15, 0x0, 0x0, 0x0, 0x0, 0x9, + 0xf1, 0x0, 0x0, 0x0, 0x2d, 0xff, 0xf9, 0x0, + 0x0, 0xe, 0xff, 0xff, 0xf7, 0x0, 0x5, 0xff, + 0xff, 0xff, 0xd0, 0x0, 0x8f, 0xff, 0xff, 0xff, + 0x0, 0xa, 0xff, 0xff, 0xff, 0xf2, 0x0, 0xdf, + 0xff, 0xff, 0xff, 0x50, 0x6f, 0xff, 0xff, 0xff, + 0xfd, 0xe, 0xff, 0xff, 0xff, 0xff, 0xf6, 0x24, + 0x44, 0x44, 0x44, 0x43, 0x0, 0x0, 0x2f, 0xf9, + 0x0, 0x0, 0x0, 0x0, 0x46, 0x0, 0x0, 0x0, + + /* U+F11C "" */ + 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf4, 0xfc, + 0x8e, 0x8e, 0x8e, 0x88, 0xe8, 0xf7, 0xf8, 0xc, + 0xc, 0xb, 0x0, 0xb0, 0xf8, 0xff, 0xec, 0xfc, + 0xec, 0xee, 0xcf, 0xf8, 0xff, 0xa0, 0xc0, 0xa0, + 0x77, 0x2f, 0xf8, 0xff, 0xec, 0xfc, 0xec, 0xee, + 0xcf, 0xf8, 0xf8, 0xc, 0x0, 0x0, 0x0, 0xb0, + 0xf8, 0xfc, 0x8e, 0x88, 0x88, 0x88, 0xe8, 0xf7, + 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf4, + + /* U+F124 "" */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0x30, 0x0, + 0x0, 0x0, 0x0, 0x18, 0xef, 0xe0, 0x0, 0x0, + 0x0, 0x29, 0xff, 0xff, 0xb0, 0x0, 0x0, 0x3a, + 0xff, 0xff, 0xff, 0x30, 0x0, 0x4c, 0xff, 0xff, + 0xff, 0xfc, 0x0, 0xb, 0xff, 0xff, 0xff, 0xff, + 0xf5, 0x0, 0xe, 0xff, 0xff, 0xff, 0xff, 0xd0, + 0x0, 0x1, 0x34, 0x44, 0xdf, 0xff, 0x60, 0x0, + 0x0, 0x0, 0x0, 0xcf, 0xfe, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xcf, 0xf8, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xcf, 0xf1, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xbf, 0x90, 0x0, 0x0, 0x0, 0x0, 0x0, 0x26, + 0x0, 0x0, 0x0, + + /* U+F15B "" */ + 0x9b, 0xbb, 0xb2, 0x70, 0xf, 0xff, 0xff, 0x4f, + 0x90, 0xff, 0xff, 0xf4, 0xff, 0x9f, 0xff, 0xff, + 0x54, 0x44, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x34, 0x44, + 0x44, 0x44, 0x30, + + /* U+F1EB "" */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x5, 0x9b, 0xcb, 0x95, 0x0, 0x0, 0x0, + 0x8f, 0xff, 0xff, 0xff, 0xff, 0x80, 0x3, 0xef, + 0xfa, 0x53, 0x23, 0x5a, 0xff, 0xe3, 0xdf, 0xa1, + 0x0, 0x0, 0x0, 0x1, 0xaf, 0xd2, 0x60, 0x5, + 0xbe, 0xfe, 0xb5, 0x0, 0x52, 0x0, 0x1c, 0xff, + 0xfe, 0xff, 0xfc, 0x10, 0x0, 0x2, 0xec, 0x40, + 0x0, 0x4c, 0xe2, 0x0, 0x0, 0x1, 0x0, 0x1, + 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0xa, 0xfa, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xf0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0xd6, 0x0, + 0x0, 0x0, + + /* U+F240 "" */ + 0x37, 0x77, 0x77, 0x77, 0x77, 0x77, 0x75, 0xf, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xf8, + 0x34, 0x44, 0x44, 0x44, 0x44, 0x4f, 0xdf, 0x8c, + 0xff, 0xff, 0xff, 0xff, 0xf2, 0xcf, 0xf8, 0xcf, + 0xff, 0xff, 0xff, 0xff, 0x8, 0xff, 0x89, 0xcc, + 0xcc, 0xcc, 0xcc, 0xc3, 0xff, 0xfb, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x9f, 0x9c, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xe1, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, + + /* U+F241 "" */ + 0x37, 0x77, 0x77, 0x77, 0x77, 0x77, 0x75, 0xf, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xf8, + 0x34, 0x44, 0x44, 0x43, 0x0, 0x4f, 0xdf, 0x8c, + 0xff, 0xff, 0xff, 0xc0, 0x2, 0xcf, 0xf8, 0xcf, + 0xff, 0xff, 0xfc, 0x0, 0x8, 0xff, 0x89, 0xcc, + 0xcc, 0xcc, 0x90, 0x3, 0xff, 0xfb, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x9f, 0x9c, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xe1, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, + + /* U+F242 "" */ + 0x37, 0x77, 0x77, 0x77, 0x77, 0x77, 0x75, 0xf, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xf8, + 0x34, 0x44, 0x42, 0x0, 0x0, 0x4f, 0xdf, 0x8c, + 0xff, 0xff, 0x80, 0x0, 0x2, 0xcf, 0xf8, 0xcf, + 0xff, 0xf8, 0x0, 0x0, 0x8, 0xff, 0x89, 0xcc, + 0xcc, 0x60, 0x0, 0x3, 0xff, 0xfb, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x9f, 0x9c, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xe1, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, + + /* U+F243 "" */ + 0x37, 0x77, 0x77, 0x77, 0x77, 0x77, 0x75, 0xf, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xf8, + 0x34, 0x41, 0x0, 0x0, 0x0, 0x4f, 0xdf, 0x8c, + 0xff, 0x40, 0x0, 0x0, 0x2, 0xcf, 0xf8, 0xcf, + 0xf4, 0x0, 0x0, 0x0, 0x8, 0xff, 0x89, 0xcc, + 0x30, 0x0, 0x0, 0x3, 0xff, 0xfb, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x9f, 0x9c, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xe1, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, + + /* U+F244 "" */ + 0x37, 0x77, 0x77, 0x77, 0x77, 0x77, 0x75, 0xf, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xf8, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x4f, 0xdf, 0x80, + 0x0, 0x0, 0x0, 0x0, 0x2, 0xcf, 0xf8, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x8, 0xff, 0x80, 0x0, + 0x0, 0x0, 0x0, 0x3, 0xff, 0xfb, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x9f, 0x9c, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xe1, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, + + /* U+F287 "" */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x25, 0xfb, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x5, 0xcb, 0xfe, 0x0, 0x0, 0x0, + 0x1, 0x0, 0xd, 0x10, 0x42, 0x0, 0x0, 0x0, + 0x9f, 0xd1, 0x68, 0x0, 0x0, 0x0, 0x68, 0x0, + 0xff, 0xfe, 0xee, 0xed, 0xdd, 0xdd, 0xef, 0xc0, + 0x9f, 0xd1, 0x0, 0xb3, 0x0, 0x0, 0x68, 0x0, + 0x1, 0x0, 0x0, 0x3b, 0x5, 0x74, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x9, 0xbe, 0xfb, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x2d, 0xfb, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + + /* U+F293 "" */ + 0x0, 0x0, 0x34, 0x20, 0x0, 0x0, 0x6e, 0xfe, + 0xfd, 0x20, 0x4, 0xff, 0xf3, 0xff, 0xd0, 0xc, + 0xff, 0xf0, 0x4f, 0xf5, 0xf, 0xd5, 0xf2, 0x95, + 0xf8, 0x2f, 0xf7, 0x41, 0x3c, 0xfa, 0x3f, 0xff, + 0x60, 0xaf, 0xfb, 0x3f, 0xfe, 0x20, 0x4f, 0xfb, + 0x2f, 0xe2, 0x92, 0x75, 0xfa, 0xf, 0xeb, 0xf1, + 0x49, 0xf8, 0x9, 0xff, 0xf0, 0x9f, 0xf2, 0x1, + 0xdf, 0xf9, 0xff, 0x90, 0x0, 0x6, 0xab, 0x95, + 0x0, + + /* U+F2ED "" */ + 0x0, 0x4, 0x88, 0x70, 0x0, 0xb, 0xcc, 0xff, + 0xff, 0xdc, 0xc5, 0xbc, 0xcc, 0xcc, 0xcc, 0xcc, + 0x52, 0x88, 0x88, 0x88, 0x88, 0x60, 0x4f, 0xff, + 0xff, 0xff, 0xfc, 0x4, 0xfa, 0xae, 0x6f, 0x5f, + 0xc0, 0x4f, 0xaa, 0xe6, 0xf4, 0xfc, 0x4, 0xfa, + 0xae, 0x6f, 0x4f, 0xc0, 0x4f, 0xaa, 0xe6, 0xf4, + 0xfc, 0x4, 0xfa, 0xae, 0x6f, 0x4f, 0xc0, 0x4f, + 0xaa, 0xe6, 0xf5, 0xfc, 0x3, 0xff, 0xff, 0xff, + 0xff, 0xb0, 0x6, 0x88, 0x88, 0x88, 0x72, 0x0, + + /* U+F304 "" */ + 0x0, 0x0, 0x0, 0x0, 0x1, 0x71, 0x0, 0x0, + 0x0, 0x0, 0x2, 0xef, 0xd1, 0x0, 0x0, 0x0, + 0x1, 0x5f, 0xff, 0xc0, 0x0, 0x0, 0x2, 0xea, + 0x5f, 0xfd, 0x0, 0x0, 0x2, 0xef, 0xfa, 0x5d, + 0x20, 0x0, 0x2, 0xef, 0xff, 0xf8, 0x0, 0x0, + 0x2, 0xef, 0xff, 0xfe, 0x20, 0x0, 0x2, 0xef, + 0xff, 0xfe, 0x20, 0x0, 0x2, 0xef, 0xff, 0xfe, + 0x20, 0x0, 0x0, 0xbf, 0xff, 0xfe, 0x20, 0x0, + 0x0, 0xd, 0xff, 0xfe, 0x20, 0x0, 0x0, 0x0, + 0xff, 0xfe, 0x20, 0x0, 0x0, 0x0, 0x6, 0x64, + 0x10, 0x0, 0x0, 0x0, 0x0, + + /* U+F55A "" */ + 0x0, 0x5, 0xef, 0xff, 0xff, 0xff, 0xff, 0x80, + 0x5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5, + 0xff, 0xff, 0x91, 0xdd, 0x19, 0xff, 0xf5, 0xff, + 0xff, 0xfd, 0x11, 0x11, 0xdf, 0xff, 0xef, 0xff, + 0xff, 0xfb, 0x0, 0xbf, 0xff, 0xf5, 0xff, 0xff, + 0xfd, 0x11, 0x11, 0xdf, 0xff, 0x5, 0xff, 0xff, + 0x91, 0xdd, 0x19, 0xff, 0xf0, 0x5, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x0, 0x4, 0xef, 0xff, + 0xff, 0xff, 0xff, 0x80, + + /* U+F7C2 "" */ + 0x0, 0x17, 0x88, 0x87, 0x20, 0x2d, 0xff, 0xff, + 0xfd, 0x2e, 0xa0, 0xb3, 0x78, 0xfe, 0xfa, 0xb, + 0x37, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0x4, 0x44, + 0x44, 0x44, 0x0, + + /* U+F8A2 "" */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x4, 0xf0, 0x0, 0x69, 0x0, + 0x0, 0x0, 0xdf, 0x0, 0x7f, 0xc0, 0x0, 0x0, + 0xd, 0xf0, 0x8f, 0xff, 0xdd, 0xdd, 0xdd, 0xff, + 0xb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xb, + 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0xc0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0 +}; + + +/*--------------------- + * GLYPH DESCRIPTION + *--------------------*/ + +static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = { + {.bitmap_index = 0, .adv_w = 0, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */, + {.bitmap_index = 0, .adv_w = 52, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 0, .adv_w = 51, .box_w = 3, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 14, .adv_w = 75, .box_w = 4, .box_h = 4, .ofs_x = 0, .ofs_y = 5}, + {.bitmap_index = 22, .adv_w = 135, .box_w = 9, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 63, .adv_w = 119, .box_w = 7, .box_h = 13, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 109, .adv_w = 162, .box_w = 10, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 154, .adv_w = 132, .box_w = 9, .box_h = 10, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 199, .adv_w = 40, .box_w = 2, .box_h = 4, .ofs_x = 0, .ofs_y = 5}, + {.bitmap_index = 203, .adv_w = 65, .box_w = 3, .box_h = 13, .ofs_x = 1, .ofs_y = -3}, + {.bitmap_index = 223, .adv_w = 65, .box_w = 3, .box_h = 13, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 243, .adv_w = 77, .box_w = 5, .box_h = 5, .ofs_x = 0, .ofs_y = 5}, + {.bitmap_index = 256, .adv_w = 112, .box_w = 7, .box_h = 6, .ofs_x = 0, .ofs_y = 2}, + {.bitmap_index = 277, .adv_w = 74, .box_w = 4, .box_h = 2, .ofs_x = 0, .ofs_y = 2}, + {.bitmap_index = 281, .adv_w = 44, .box_w = 3, .box_h = 2, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 284, .adv_w = 68, .box_w = 6, .box_h = 13, .ofs_x = -1, .ofs_y = -1}, + {.bitmap_index = 323, .adv_w = 128, .box_w = 8, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 359, .adv_w = 71, .box_w = 4, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 377, .adv_w = 110, .box_w = 7, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 409, .adv_w = 110, .box_w = 7, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 441, .adv_w = 128, .box_w = 8, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 477, .adv_w = 110, .box_w = 7, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 509, .adv_w = 118, .box_w = 8, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 545, .adv_w = 115, .box_w = 7, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 577, .adv_w = 124, .box_w = 8, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 613, .adv_w = 118, .box_w = 7, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 645, .adv_w = 44, .box_w = 3, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 656, .adv_w = 44, .box_w = 3, .box_h = 9, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 670, .adv_w = 112, .box_w = 7, .box_h = 7, .ofs_x = 0, .ofs_y = 1}, + {.bitmap_index = 695, .adv_w = 112, .box_w = 7, .box_h = 5, .ofs_x = 0, .ofs_y = 2}, + {.bitmap_index = 713, .adv_w = 112, .box_w = 7, .box_h = 7, .ofs_x = 0, .ofs_y = 1}, + {.bitmap_index = 738, .adv_w = 110, .box_w = 7, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 770, .adv_w = 199, .box_w = 12, .box_h = 12, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 842, .adv_w = 141, .box_w = 10, .box_h = 9, .ofs_x = -1, .ofs_y = 0}, + {.bitmap_index = 887, .adv_w = 145, .box_w = 8, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 923, .adv_w = 139, .box_w = 9, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 964, .adv_w = 159, .box_w = 9, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1005, .adv_w = 129, .box_w = 7, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1037, .adv_w = 122, .box_w = 7, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1069, .adv_w = 148, .box_w = 9, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1110, .adv_w = 156, .box_w = 8, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1146, .adv_w = 60, .box_w = 2, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1155, .adv_w = 98, .box_w = 6, .box_h = 9, .ofs_x = -1, .ofs_y = 0}, + {.bitmap_index = 1182, .adv_w = 138, .box_w = 8, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1218, .adv_w = 114, .box_w = 7, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1250, .adv_w = 183, .box_w = 10, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1295, .adv_w = 156, .box_w = 8, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1331, .adv_w = 161, .box_w = 10, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1376, .adv_w = 139, .box_w = 8, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1412, .adv_w = 161, .box_w = 10, .box_h = 12, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 1472, .adv_w = 140, .box_w = 8, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1508, .adv_w = 119, .box_w = 7, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1540, .adv_w = 113, .box_w = 7, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1572, .adv_w = 152, .box_w = 8, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1608, .adv_w = 137, .box_w = 10, .box_h = 9, .ofs_x = -1, .ofs_y = 0}, + {.bitmap_index = 1653, .adv_w = 216, .box_w = 14, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1716, .adv_w = 129, .box_w = 8, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1752, .adv_w = 124, .box_w = 9, .box_h = 9, .ofs_x = -1, .ofs_y = 0}, + {.bitmap_index = 1793, .adv_w = 126, .box_w = 8, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1829, .adv_w = 64, .box_w = 3, .box_h = 13, .ofs_x = 1, .ofs_y = -3}, + {.bitmap_index = 1849, .adv_w = 68, .box_w = 6, .box_h = 13, .ofs_x = -1, .ofs_y = -1}, + {.bitmap_index = 1888, .adv_w = 64, .box_w = 3, .box_h = 13, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 1908, .adv_w = 112, .box_w = 7, .box_h = 6, .ofs_x = 0, .ofs_y = 2}, + {.bitmap_index = 1929, .adv_w = 96, .box_w = 6, .box_h = 1, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 1932, .adv_w = 115, .box_w = 4, .box_h = 2, .ofs_x = 1, .ofs_y = 8}, + {.bitmap_index = 1936, .adv_w = 115, .box_w = 7, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1961, .adv_w = 131, .box_w = 7, .box_h = 10, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1996, .adv_w = 110, .box_w = 7, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 2021, .adv_w = 131, .box_w = 8, .box_h = 10, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 2061, .adv_w = 118, .box_w = 7, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 2086, .adv_w = 68, .box_w = 5, .box_h = 10, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 2111, .adv_w = 132, .box_w = 8, .box_h = 10, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 2151, .adv_w = 131, .box_w = 7, .box_h = 10, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2186, .adv_w = 54, .box_w = 3, .box_h = 10, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 2201, .adv_w = 55, .box_w = 5, .box_h = 13, .ofs_x = -2, .ofs_y = -3}, + {.bitmap_index = 2234, .adv_w = 118, .box_w = 7, .box_h = 10, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2269, .adv_w = 54, .box_w = 2, .box_h = 10, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2279, .adv_w = 203, .box_w = 11, .box_h = 7, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2318, .adv_w = 131, .box_w = 7, .box_h = 7, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2343, .adv_w = 122, .box_w = 8, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 2371, .adv_w = 131, .box_w = 7, .box_h = 10, .ofs_x = 1, .ofs_y = -3}, + {.bitmap_index = 2406, .adv_w = 131, .box_w = 8, .box_h = 10, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 2446, .adv_w = 79, .box_w = 4, .box_h = 7, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2460, .adv_w = 96, .box_w = 6, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 2481, .adv_w = 79, .box_w = 5, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 2504, .adv_w = 130, .box_w = 7, .box_h = 7, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2529, .adv_w = 107, .box_w = 8, .box_h = 7, .ofs_x = -1, .ofs_y = 0}, + {.bitmap_index = 2557, .adv_w = 173, .box_w = 11, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 2596, .adv_w = 106, .box_w = 7, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 2621, .adv_w = 107, .box_w = 8, .box_h = 10, .ofs_x = -1, .ofs_y = -3}, + {.bitmap_index = 2661, .adv_w = 100, .box_w = 6, .box_h = 7, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 2682, .adv_w = 67, .box_w = 4, .box_h = 13, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 2708, .adv_w = 57, .box_w = 2, .box_h = 13, .ofs_x = 1, .ofs_y = -3}, + {.bitmap_index = 2721, .adv_w = 67, .box_w = 4, .box_h = 13, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 2747, .adv_w = 112, .box_w = 7, .box_h = 2, .ofs_x = 0, .ofs_y = 4}, + {.bitmap_index = 2754, .adv_w = 192, .box_w = 12, .box_h = 13, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 2832, .adv_w = 192, .box_w = 12, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 2886, .adv_w = 192, .box_w = 12, .box_h = 11, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 2952, .adv_w = 192, .box_w = 12, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 3006, .adv_w = 132, .box_w = 9, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 3047, .adv_w = 192, .box_w = 12, .box_h = 13, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 3125, .adv_w = 192, .box_w = 12, .box_h = 13, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 3203, .adv_w = 216, .box_w = 14, .box_h = 11, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 3280, .adv_w = 192, .box_w = 12, .box_h = 13, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 3358, .adv_w = 216, .box_w = 14, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 3421, .adv_w = 192, .box_w = 12, .box_h = 13, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 3499, .adv_w = 96, .box_w = 6, .box_h = 10, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 3529, .adv_w = 144, .box_w = 9, .box_h = 10, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 3574, .adv_w = 216, .box_w = 14, .box_h = 13, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 3665, .adv_w = 192, .box_w = 12, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 3719, .adv_w = 168, .box_w = 8, .box_h = 12, .ofs_x = 1, .ofs_y = -2}, + {.bitmap_index = 3767, .adv_w = 168, .box_w = 11, .box_h = 13, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 3839, .adv_w = 168, .box_w = 11, .box_h = 11, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 3900, .adv_w = 168, .box_w = 11, .box_h = 11, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 3961, .adv_w = 168, .box_w = 8, .box_h = 12, .ofs_x = 1, .ofs_y = -2}, + {.bitmap_index = 4009, .adv_w = 168, .box_w = 12, .box_h = 11, .ofs_x = -1, .ofs_y = -1}, + {.bitmap_index = 4075, .adv_w = 120, .box_w = 7, .box_h = 11, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 4114, .adv_w = 120, .box_w = 7, .box_h = 11, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 4153, .adv_w = 168, .box_w = 11, .box_h = 11, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 4214, .adv_w = 168, .box_w = 11, .box_h = 3, .ofs_x = 0, .ofs_y = 3}, + {.bitmap_index = 4231, .adv_w = 216, .box_w = 14, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 4294, .adv_w = 240, .box_w = 16, .box_h = 13, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 4398, .adv_w = 216, .box_w = 15, .box_h = 13, .ofs_x = -1, .ofs_y = -2}, + {.bitmap_index = 4496, .adv_w = 192, .box_w = 12, .box_h = 11, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 4562, .adv_w = 168, .box_w = 11, .box_h = 7, .ofs_x = 0, .ofs_y = 1}, + {.bitmap_index = 4601, .adv_w = 168, .box_w = 11, .box_h = 7, .ofs_x = 0, .ofs_y = 1}, + {.bitmap_index = 4640, .adv_w = 240, .box_w = 16, .box_h = 10, .ofs_x = -1, .ofs_y = 0}, + {.bitmap_index = 4720, .adv_w = 192, .box_w = 12, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 4774, .adv_w = 192, .box_w = 12, .box_h = 13, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 4852, .adv_w = 192, .box_w = 13, .box_h = 13, .ofs_x = -1, .ofs_y = -2}, + {.bitmap_index = 4937, .adv_w = 168, .box_w = 11, .box_h = 11, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 4998, .adv_w = 168, .box_w = 11, .box_h = 13, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 5070, .adv_w = 168, .box_w = 11, .box_h = 11, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 5131, .adv_w = 120, .box_w = 9, .box_h = 13, .ofs_x = -1, .ofs_y = -2}, + {.bitmap_index = 5190, .adv_w = 168, .box_w = 11, .box_h = 13, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 5262, .adv_w = 168, .box_w = 11, .box_h = 13, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 5334, .adv_w = 216, .box_w = 14, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 5397, .adv_w = 192, .box_w = 14, .box_h = 13, .ofs_x = -1, .ofs_y = -2}, + {.bitmap_index = 5488, .adv_w = 144, .box_w = 9, .box_h = 13, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 5547, .adv_w = 240, .box_w = 15, .box_h = 12, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 5637, .adv_w = 240, .box_w = 15, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 5705, .adv_w = 240, .box_w = 15, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 5773, .adv_w = 240, .box_w = 15, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 5841, .adv_w = 240, .box_w = 15, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 5909, .adv_w = 240, .box_w = 15, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 5977, .adv_w = 240, .box_w = 16, .box_h = 11, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 6065, .adv_w = 168, .box_w = 10, .box_h = 13, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 6130, .adv_w = 168, .box_w = 11, .box_h = 13, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 6202, .adv_w = 192, .box_w = 13, .box_h = 13, .ofs_x = -1, .ofs_y = -2}, + {.bitmap_index = 6287, .adv_w = 240, .box_w = 15, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 6355, .adv_w = 144, .box_w = 9, .box_h = 13, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 6414, .adv_w = 193, .box_w = 13, .box_h = 9, .ofs_x = 0, .ofs_y = 0} +}; + +/*--------------------- + * CHARACTER MAPPING + *--------------------*/ + +static const uint16_t unicode_list_2[] = { + 0x0, 0x7, 0xa, 0xb, 0xc, 0x10, 0x12, 0x14, + 0x18, 0x1b, 0x20, 0x25, 0x26, 0x27, 0x3d, 0x47, + 0x4a, 0x4b, 0x4c, 0x50, 0x51, 0x52, 0x53, 0x66, + 0x67, 0x6d, 0x6f, 0x70, 0x73, 0x76, 0x77, 0x78, + 0x7a, 0x92, 0x94, 0xc3, 0xc4, 0xc6, 0xe6, 0xe9, + 0xf2, 0x11b, 0x123, 0x15a, 0x1ea, 0x23f, 0x240, 0x241, + 0x242, 0x243, 0x286, 0x292, 0x2ec, 0x303, 0x559, 0x7c1, + 0x8a1 +}; + +/*Collect the unicode lists and glyph_id offsets*/ +static const lv_font_fmt_txt_cmap_t cmaps[] = +{ + { + .range_start = 32, .range_length = 12, .glyph_id_start = 1, + .unicode_list = NULL, .glyph_id_ofs_list = NULL, .list_length = 0, .type = LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY + }, + { + .range_start = 45, .range_length = 82, .glyph_id_start = 13, + .unicode_list = NULL, .glyph_id_ofs_list = NULL, .list_length = 0, .type = LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY + }, + { + .range_start = 61441, .range_length = 2210, .glyph_id_start = 95, + .unicode_list = unicode_list_2, .glyph_id_ofs_list = NULL, .list_length = 57, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY + } +}; + +/*----------------- + * KERNING + *----------------*/ + + +/*Map glyph_ids to kern left classes*/ +static const uint8_t kern_left_class_mapping[] = +{ + 0, 0, 1, 2, 0, 3, 4, 5, + 2, 6, 7, 8, 9, 9, 10, 11, + 12, 0, 13, 14, 15, 16, 17, 18, + 19, 12, 20, 20, 0, 0, 0, 21, + 22, 23, 24, 25, 22, 26, 27, 28, + 29, 29, 30, 31, 32, 29, 29, 22, + 33, 34, 35, 3, 36, 30, 37, 37, + 38, 39, 40, 41, 42, 43, 0, 44, + 0, 45, 46, 47, 48, 49, 50, 51, + 45, 52, 52, 53, 48, 45, 45, 46, + 46, 54, 55, 56, 57, 51, 58, 58, + 59, 58, 60, 41, 0, 0, 9, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/*Map glyph_ids to kern right classes*/ +static const uint8_t kern_right_class_mapping[] = +{ + 0, 0, 1, 2, 0, 3, 4, 5, + 2, 6, 7, 8, 9, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 12, 18, + 19, 20, 21, 21, 0, 0, 0, 22, + 23, 24, 25, 23, 25, 25, 25, 23, + 25, 25, 26, 25, 25, 25, 25, 23, + 25, 23, 25, 3, 27, 28, 29, 29, + 30, 31, 32, 33, 34, 35, 0, 36, + 0, 37, 38, 39, 39, 39, 0, 39, + 38, 40, 41, 38, 38, 42, 42, 39, + 42, 39, 42, 43, 44, 45, 46, 46, + 47, 46, 48, 0, 0, 35, 9, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/*Kern values between classes*/ +static const int8_t kern_class_values[] = +{ + 0, 1, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 2, 0, 0, 0, + 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 9, 0, 5, -4, 0, 0, 0, + 0, -11, -12, 1, 9, 4, 3, -8, + 1, 9, 1, 8, 2, 6, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 12, 2, -1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, -6, 0, 0, 0, 0, 0, -4, + 3, 4, 0, 0, -2, 0, -1, 2, + 0, -2, 0, -2, -1, -4, 0, 0, + 0, 0, -2, 0, 0, -2, -3, 0, + 0, -2, 0, -4, 0, 0, 0, 0, + 0, 0, 0, 0, 0, -2, -2, 0, + 0, -5, 0, -23, 0, 0, -4, 0, + 4, 6, 0, 0, -4, 2, 2, 6, + 4, -3, 4, 0, 0, -11, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, -7, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + -2, -9, 0, -8, -1, 0, 0, 0, + 0, 0, 7, 0, -6, -2, -1, 1, + 0, -3, 0, 0, -1, -14, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, -15, -2, 7, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 6, 0, 2, 0, 0, -4, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 7, 2, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 4, 2, 6, -2, 0, 0, 4, + -2, -6, -26, 1, 5, 4, 0, -2, + 0, 7, 0, 6, 0, 6, 0, -18, + 0, -2, 6, 0, 6, -2, 4, 2, + 0, 0, 1, -2, 0, 0, -3, 15, + 0, 15, 0, 6, 0, 8, 2, 3, + 0, 0, 0, -7, 0, 0, 0, 0, + 1, -1, 0, 1, -3, -2, -4, 1, + 0, -2, 0, 0, 0, -8, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, -12, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, -11, 0, -12, 0, 0, 0, 0, + -1, 0, 19, -2, -2, 2, 2, -2, + 0, -2, 2, 0, 0, -10, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, -19, 0, 2, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 12, 0, 0, -7, 0, 6, 0, + -13, -19, -13, -4, 6, 0, 0, -13, + 0, 2, -4, 0, -3, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 5, 6, -23, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, 0, 1, + 1, -2, -4, 0, -1, -1, -2, 0, + 0, -1, 0, 0, 0, -4, 0, -2, + 0, -4, -4, 0, -5, -6, -6, -4, + 0, -4, 0, -4, 0, 0, 0, 0, + -2, 0, 0, 2, 0, 1, -2, 0, + 0, 0, 0, 2, -1, 0, 0, 0, + -1, 2, 2, -1, 0, 0, 0, -4, + 0, -1, 0, 0, 0, 0, 0, 1, + 0, 2, -1, 0, -2, 0, -3, 0, + 0, -1, 0, 6, 0, 0, -2, 0, + 0, 0, 0, 0, -1, 1, -1, -1, + 0, -2, 0, -2, 0, 0, 0, 0, + 0, 0, 0, 0, 0, -1, -1, 0, + -2, -2, 0, 0, 0, 0, 0, 1, + 0, 0, -1, 0, -2, -2, -2, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + -1, 0, 0, 0, 0, -1, -2, 0, + 0, -6, -1, -6, 4, 0, 0, -4, + 2, 4, 5, 0, -5, -1, -2, 0, + -1, -9, 2, -1, 1, -10, 2, 0, + 0, 1, -10, 0, -10, -2, -17, -1, + 0, -10, 0, 4, 5, 0, 2, 0, + 0, 0, 0, 0, 0, -3, -2, 0, + 0, 0, 0, -2, 0, 0, 0, -2, + 0, 0, 0, 0, 0, -1, -1, 0, + -1, -2, 0, 0, 0, 0, 0, 0, + 0, -2, -2, 0, -1, -2, -2, 0, + 0, -2, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, -2, -2, 0, + 0, -1, 0, -4, 2, 0, 0, -2, + 1, 2, 2, 0, 0, 0, 0, 0, + 0, -1, 0, 0, 0, 0, 0, 1, + 0, 0, -2, 0, -2, -1, -2, 0, + 0, 0, 0, 0, 0, 0, 2, 0, + -2, 0, 0, 0, 0, -2, -3, 0, + 0, 6, -1, 1, -6, 0, 0, 5, + -10, -10, -8, -4, 2, 0, -2, -12, + -3, 0, -3, 0, -4, 3, -3, -12, + 0, -5, 0, 0, 1, -1, 2, -1, + 0, 2, 0, -6, -7, 0, -10, -5, + -4, -5, -6, -2, -5, 0, -4, -5, + 0, 1, 0, -2, 0, 0, 0, 1, + 0, 2, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, -2, 0, -1, + 0, -1, -2, 0, -3, -4, -4, -1, + 0, -6, 0, 0, 0, 0, 0, 0, + -2, 0, 0, 0, 0, 1, -1, 0, + 0, 2, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, -2, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, -3, 0, 2, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + -1, 0, 0, 0, -4, 0, 0, 0, + 0, -10, -6, 0, 0, 0, -3, -10, + 0, 0, -2, 2, 0, -5, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + -3, 0, 0, -4, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, -3, 0, 0, 0, 0, 2, 0, + 1, -4, -4, 0, -2, -2, -2, 0, + 0, 0, 0, 0, 0, -6, 0, -2, + 0, -3, -2, 0, -4, -5, -6, -2, + 0, -4, 0, -6, 0, 0, 0, 0, + 15, 0, 0, 1, 0, 0, -2, 0, + 0, -8, 0, 0, 0, 0, 0, -18, + -3, 6, 6, -2, -8, 0, 2, -3, + 0, -10, -1, -2, 2, -13, -2, 2, + 0, 3, -7, -3, -7, -6, -8, 0, + 0, -12, 0, 11, 0, 0, -1, 0, + 0, 0, -1, -1, -2, -5, -6, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -2, 0, -1, -2, -3, 0, + 0, -4, 0, -2, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -1, 0, -4, 0, 0, 4, + -1, 2, 0, -4, 2, -1, -1, -5, + -2, 0, -2, -2, -1, 0, -3, -3, + 0, 0, -2, -1, -1, -3, -2, 0, + 0, -2, 0, 2, -1, 0, -4, 0, + 0, 0, -4, 0, -3, 0, -3, -3, + 0, 0, 0, 0, 0, 0, 0, 0, + -4, 2, 0, -3, 0, -1, -2, -6, + -1, -1, -1, -1, -1, -2, -1, 0, + 0, 0, 0, 0, -2, -2, -2, 0, + 0, 0, 0, 2, -1, 0, -1, 0, + 0, 0, -1, -2, -1, -2, -2, -2, + 2, 8, -1, 0, -5, 0, -1, 4, + 0, -2, -8, -2, 3, 0, 0, -9, + -3, 2, -3, 1, 0, -1, -2, -6, + 0, -3, 1, 0, 0, -3, 0, 0, + 0, 2, 2, -4, -4, 0, -3, -2, + -3, -2, -2, 0, -3, 1, -4, -3, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, -3, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, -1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, -2, -2, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, -3, + 0, 0, -2, 0, 0, -2, -2, 0, + 0, 0, 0, -2, 0, 0, 0, 0, + -1, 0, 0, 0, 0, 0, -1, 0, + 0, 0, -3, 0, -4, 0, 0, 0, + -6, 0, 1, -4, 4, 0, -1, -9, + 0, 0, -4, -2, 0, -8, -5, -5, + 0, 0, -8, -2, -8, -7, -9, 0, + -5, 0, 2, 13, -2, 0, -4, -2, + -1, -2, -3, -5, -3, -7, -8, -4, + 0, 0, -1, 0, 1, 0, 0, -13, + -2, 6, 4, -4, -7, 0, 1, -6, + 0, -10, -1, -2, 4, -18, -2, 1, + 0, 0, -12, -2, -10, -2, -14, 0, + 0, -13, 0, 11, 1, 0, -1, 0, + 0, 0, 0, -1, -1, -7, -1, 0, + 0, 0, 0, 0, -6, 0, -2, 0, + -1, -5, -9, 0, 0, -1, -3, -6, + -2, 0, -1, 0, 0, 0, 0, -9, + -2, -6, -6, -2, -3, -5, -2, -3, + 0, -4, -2, -6, -3, 0, -2, -4, + -2, -4, 0, 1, 0, -1, -6, 0, + 0, -3, 0, 0, 0, 0, 2, 0, + 1, -4, 8, 0, -2, -2, -2, 0, + 0, 0, 0, 0, 0, -6, 0, -2, + 0, -3, -2, 0, -4, -5, -6, -2, + 0, -4, 2, 8, 0, 0, 0, 0, + 15, 0, 0, 1, 0, 0, -2, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, -1, -4, + 0, 0, 0, 0, 0, -1, 0, 0, + 0, -2, -2, 0, 0, -4, -2, 0, + 0, -4, 0, 3, -1, 0, 0, 0, + 0, 0, 0, 1, 0, 0, 0, 0, + 4, 2, -2, 0, -6, -3, 0, 6, + -6, -6, -4, -4, 8, 3, 2, -17, + -1, 4, -2, 0, -2, 2, -2, -7, + 0, -2, 2, -2, -2, -6, -2, 0, + 0, 6, 4, 0, -5, 0, -11, -2, + 6, -2, -7, 1, -2, -6, -6, -2, + 2, 0, -3, 0, -5, 0, 2, 6, + -4, -7, -8, -5, 6, 0, 1, -14, + -2, 2, -3, -1, -4, 0, -4, -7, + -3, -3, -2, 0, 0, -4, -4, -2, + 0, 6, 4, -2, -11, 0, -11, -3, + 0, -7, -11, -1, -6, -3, -6, -5, + 0, 0, -2, 0, -4, -2, 0, -2, + -3, 0, 3, -6, 2, 0, 0, -10, + 0, -2, -4, -3, -1, -6, -5, -6, + -4, 0, -6, -2, -4, -4, -6, -2, + 0, 0, 1, 9, -3, 0, -6, -2, + 0, -2, -4, -4, -5, -5, -7, -2, + 4, 0, -3, 0, -10, -2, 1, 4, + -6, -7, -4, -6, 6, -2, 1, -18, + -3, 4, -4, -3, -7, 0, -6, -8, + -2, -2, -2, -2, -4, -6, -1, 0, + 0, 6, 5, -1, -12, 0, -12, -4, + 5, -7, -13, -4, -7, -8, -10, -6, + 0, 0, 0, 0, -2, 0, 0, 2, + -2, 4, 1, -4, 4, 0, 0, -6, + -1, 0, -1, 0, 1, 1, -2, 0, + 0, 0, 0, 0, 0, -2, 0, 0, + 0, 0, 2, 6, 0, 0, -2, 0, + 0, 0, 0, -1, -1, -2, 0, 0, + 1, 2, 0, 0, 0, 0, 2, 0, + -2, 0, 7, 0, 3, 1, 1, -2, + 0, 4, 0, 0, 0, 2, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 6, 0, 5, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, -12, 0, -2, 3, 0, 6, 0, + 0, 19, 2, -4, -4, 2, 2, -1, + 1, -10, 0, 0, 9, -12, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, -13, 7, 27, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -3, 0, 0, -4, -2, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, -1, 0, -5, 0, 0, 1, 0, + 0, 2, 25, -4, -2, 6, 5, -5, + 2, 0, 0, 2, 2, -2, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, -25, 5, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, -5, 0, 0, 0, -5, + 0, 0, 0, 0, -4, -1, 0, 0, + 0, -4, 0, -2, 0, -9, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, -13, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, -2, 0, 0, + 0, -3, 0, -5, 0, 0, 0, -3, + 2, -2, 0, 0, -5, -2, -4, 0, + 0, -5, 0, -2, 0, -9, 0, -2, + 0, 0, -16, -4, -8, -2, -7, 0, + 0, -13, 0, -5, -1, 0, 0, 0, + 0, 0, 0, 0, 0, -3, -3, -2, + 0, 0, 0, 0, -4, 0, -4, 2, + -2, 4, 0, -1, -4, -1, -3, -4, + 0, -2, -1, -1, 1, -5, -1, 0, + 0, 0, -17, -2, -3, 0, -4, 0, + -1, -9, -2, 0, 0, -1, -2, 0, + 0, 0, 0, 1, 0, -1, -3, -1, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2, 0, 0, 0, 0, + 0, -4, 0, -1, 0, 0, 0, -4, + 2, 0, 0, 0, -5, -2, -4, 0, + 0, -5, 0, -2, 0, -9, 0, 0, + 0, 0, -19, 0, -4, -7, -10, 0, + 0, -13, 0, -1, -3, 0, 0, 0, + 0, 0, 0, 0, 0, -2, -3, -1, + 1, 0, 0, 3, -2, 0, 6, 9, + -2, -2, -6, 2, 9, 3, 4, -5, + 2, 8, 2, 6, 4, 5, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 12, 9, -3, -2, 0, -2, 15, + 8, 15, 0, 0, 0, 2, 0, 0, + 0, 0, -3, 0, 0, 0, 0, 0, + 0, 0, 0, 0, -1, 0, 0, 0, + 0, 0, 0, 0, 0, 3, 0, 0, + 0, 0, -16, -2, -2, -8, -9, 0, + 0, -13, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -3, 0, 0, 0, 0, 0, + 0, 0, 0, 0, -1, 0, 0, 0, + 0, 0, 0, 0, 0, 3, 0, 0, + 0, 0, -16, -2, -2, -8, -9, 0, + 0, -8, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, -2, 0, 0, 0, + -4, 2, 0, -2, 2, 3, 2, -6, + 0, 0, -2, 2, 0, 2, 0, 0, + 0, 0, -5, 0, -2, -1, -4, 0, + -2, -8, 0, 12, -2, 0, -4, -1, + 0, -1, -3, 0, -2, -5, -4, -2, + 0, 0, -3, 0, 0, 0, 0, 0, + 0, 0, 0, 0, -1, 0, 0, 0, + 0, 0, 0, 0, 0, 3, 0, 0, + 0, 0, -16, -2, -2, -8, -9, 0, + 0, -13, 0, 0, 0, 0, 0, 0, + 10, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -3, 0, -6, -2, -2, 6, + -2, -2, -8, 1, -1, 1, -1, -5, + 0, 4, 0, 2, 1, 2, -5, -8, + -2, 0, -7, -4, -5, -8, -7, 0, + -3, -4, -2, -2, -2, -1, -2, -1, + 0, -1, -1, 3, 0, 3, -1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, -1, -2, -2, 0, + 0, -5, 0, -1, 0, -3, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, -12, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, -2, -2, 0, + 0, 0, 0, 0, -2, 0, 0, -3, + -2, 2, 0, -3, -4, -1, 0, -6, + -1, -4, -1, -2, 0, -3, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, -13, 0, 6, 0, 0, -3, 0, + 0, 0, 0, -2, 0, -2, 0, 0, + 0, 0, -1, 0, -4, 0, 0, 8, + -2, -6, -6, 1, 2, 2, 0, -5, + 1, 3, 1, 6, 1, 6, -1, -5, + 0, 0, -8, 0, 0, -6, -5, 0, + 0, -4, 0, -2, -3, 0, -3, 0, + -3, 0, -1, 3, 0, -2, -6, -2, + 0, 0, -2, 0, -4, 0, 0, 2, + -4, 0, 2, -2, 2, 0, 0, -6, + 0, -1, -1, 0, -2, 2, -2, 0, + 0, 0, -8, -2, -4, 0, -6, 0, + 0, -9, 0, 7, -2, 0, -3, 0, + 1, 0, -2, 0, -2, -6, 0, -2, + 0, 0, 0, 0, -1, 0, 0, 2, + -2, 1, 0, 0, -2, -1, 0, -2, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, -12, 0, 4, 0, 0, -2, 0, + 0, 0, 0, 0, 0, -2, -2, 0 +}; + + +/*Collect the kern class' data in one place*/ +static const lv_font_fmt_txt_kern_classes_t kern_classes = +{ + .class_pair_values = kern_class_values, + .left_class_mapping = kern_left_class_mapping, + .right_class_mapping = kern_right_class_mapping, + .left_class_cnt = 60, + .right_class_cnt = 48, +}; + +/*-------------------- + * ALL CUSTOM DATA + *--------------------*/ + +#if LV_VERSION_CHECK(8, 0, 0) +/*Store all the custom data of the font*/ +static lv_font_fmt_txt_glyph_cache_t cache; +static const lv_font_fmt_txt_dsc_t font_dsc = { +#else +static lv_font_fmt_txt_dsc_t font_dsc = { +#endif + .glyph_bitmap = glyph_bitmap, + .glyph_dsc = glyph_dsc, + .cmaps = cmaps, + .kern_dsc = &kern_classes, + .kern_scale = 16, + .cmap_num = 3, + .bpp = 4, + .kern_classes = 1, + .bitmap_format = 0, +#if LV_VERSION_CHECK(8, 0, 0) + .cache = &cache +#endif +}; + + +/*----------------- + * PUBLIC FONT + *----------------*/ + +/*Initialize a public general font descriptor*/ +#if LV_VERSION_CHECK(8, 0, 0) +const lv_font_t lv_font_montserratMedium_12 = { +#else +lv_font_t lv_font_montserratMedium_12 = { +#endif + .get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/ + .get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/ + .line_height = 12, /*The maximum line height required by the font default: (f.src.ascent - f.src.descent)*/ + .base_line = 1.7999999999999998, /*Baseline measured from the bottom of the line*/ +#if !(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0) + .subpx = LV_FONT_SUBPX_NONE, +#endif +#if LV_VERSION_CHECK(7, 4, 0) || LVGL_VERSION_MAJOR >= 8 + .underline_position = -1, + .underline_thickness = 1, +#endif + .dsc = &font_dsc /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */ +}; + + + +#endif /*#if LV_FONT_MONTSERRATMEDIUM_12*/ + diff --git a/code/08.gui/lvgl_spd2010_gui/main/ui/generated/guider_fonts/lv_font_montserratMedium_16.c b/code/08.gui/lvgl_spd2010_gui/main/ui/generated/guider_fonts/lv_font_montserratMedium_16.c new file mode 100644 index 0000000..ebcd0c5 --- /dev/null +++ b/code/08.gui/lvgl_spd2010_gui/main/ui/generated/guider_fonts/lv_font_montserratMedium_16.c @@ -0,0 +1,2411 @@ +/* + * Copyright 2024 NXP + * NXP Confidential and Proprietary. This software is owned or controlled by NXP and may only be used strictly in + * accordance with the applicable license terms. By expressly accepting such terms or by downloading, installing, + * activating and/or otherwise using the software, you are agreeing that you have read, and that you agree to + * comply with and are bound by, such license terms. If you do not agree to be bound by the applicable license + * terms, then you may not retain, install, activate or otherwise use the software. + */ +/******************************************************************************* + * Size: 16 px + * Bpp: 4 + * Opts: --user-data-dir=C:\Users\duruofu\AppData\Roaming\gui-guider --app-path=C:\NXP\GUI-Guider-1.6.1-GA\resources\app.asar --no-sandbox --no-zygote --lang=zh-CN --device-scale-factor=1.25 --num-raster-threads=4 --enable-main-frame-before-activation --renderer-client-id=5 --time-ticks-at-unix-epoch=-1717375277958826 --launch-time-ticks=92300759598 --mojo-platform-channel-handle=3020 --field-trial-handle=1732,i,14137332758556215245,7603498977609116181,131072 --disable-features=SpareRendererForSitePerProcess,WinRetrieveSuggestionsOnlyOnDemand /prefetch:1 + ******************************************************************************/ + +#ifdef LV_LVGL_H_INCLUDE_SIMPLE +#include "lvgl.h" +#else +#include "lvgl.h" +#endif + +#ifndef LV_FONT_MONTSERRATMEDIUM_16 +#define LV_FONT_MONTSERRATMEDIUM_16 1 +#endif + +#if LV_FONT_MONTSERRATMEDIUM_16 + +/*----------------- + * BITMAPS + *----------------*/ + +/*Store the image of the glyphs*/ +static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = { + /* U+0020 " " */ + + /* U+0021 "!" */ + 0xbf, 0xb, 0xf0, 0xaf, 0xa, 0xe0, 0x9e, 0x8, + 0xd0, 0x8c, 0x7, 0xc0, 0x0, 0x0, 0x10, 0xbf, + 0x1a, 0xe0, + + /* U+0022 "\"" */ + 0xf5, 0x1f, 0x3f, 0x51, 0xf3, 0xe4, 0xf, 0x3e, + 0x40, 0xf2, 0x72, 0x8, 0x10, + + /* U+0023 "#" */ + 0x0, 0x5, 0xc0, 0x3, 0xe0, 0x0, 0x0, 0x7a, + 0x0, 0x5c, 0x0, 0x0, 0x9, 0x80, 0x7, 0xa0, + 0x1, 0xff, 0xff, 0xff, 0xff, 0xfd, 0x3, 0x3e, + 0x73, 0x3c, 0x83, 0x30, 0x0, 0xf2, 0x0, 0xc5, + 0x0, 0x0, 0xf, 0x10, 0xe, 0x30, 0x0, 0x2, + 0xf0, 0x0, 0xf2, 0x0, 0x9f, 0xff, 0xff, 0xff, + 0xff, 0x41, 0x38, 0xc3, 0x36, 0xe3, 0x30, 0x0, + 0x89, 0x0, 0x5c, 0x0, 0x0, 0xa, 0x70, 0x7, + 0xa0, 0x0, + + /* U+0024 "$" */ + 0x0, 0x0, 0x79, 0x0, 0x0, 0x0, 0x0, 0x79, + 0x0, 0x0, 0x0, 0x5c, 0xff, 0xe9, 0x20, 0x6, + 0xfc, 0xbc, 0x9e, 0x90, 0xe, 0xb0, 0x79, 0x0, + 0x10, 0xf, 0x80, 0x79, 0x0, 0x0, 0xd, 0xf5, + 0x79, 0x0, 0x0, 0x3, 0xef, 0xfd, 0x50, 0x0, + 0x0, 0x6, 0xcf, 0xfe, 0x40, 0x0, 0x0, 0x79, + 0x5e, 0xf1, 0x0, 0x0, 0x79, 0x5, 0xf3, 0x7, + 0x0, 0x79, 0x7, 0xf1, 0x2f, 0xe9, 0xbc, 0xaf, + 0xa0, 0x3, 0xae, 0xff, 0xd7, 0x0, 0x0, 0x0, + 0x79, 0x0, 0x0, 0x0, 0x0, 0x79, 0x0, 0x0, + + /* U+0025 "%" */ + 0x3, 0xde, 0x80, 0x0, 0x5, 0xd0, 0x0, 0xe4, + 0xc, 0x50, 0x1, 0xe3, 0x0, 0x4c, 0x0, 0x5a, + 0x0, 0xa9, 0x0, 0x6, 0xa0, 0x4, 0xc0, 0x4e, + 0x0, 0x0, 0x4c, 0x0, 0x5a, 0xd, 0x50, 0x0, + 0x0, 0xe4, 0x1c, 0x58, 0xa0, 0x0, 0x0, 0x3, + 0xce, 0x73, 0xe1, 0x3c, 0xe9, 0x0, 0x0, 0x0, + 0xd6, 0xe, 0x40, 0xa8, 0x0, 0x0, 0x7c, 0x3, + 0xc0, 0x3, 0xd0, 0x0, 0x2e, 0x20, 0x3c, 0x0, + 0x3d, 0x0, 0xb, 0x70, 0x0, 0xe2, 0x9, 0x80, + 0x6, 0xd0, 0x0, 0x4, 0xdd, 0xa0, + + /* U+0026 "&" */ + 0x0, 0x9, 0xef, 0xb1, 0x0, 0x0, 0x9, 0xe4, + 0x3c, 0xa0, 0x0, 0x0, 0xd9, 0x0, 0x7d, 0x0, + 0x0, 0xc, 0xc0, 0x1c, 0xa0, 0x0, 0x0, 0x3f, + 0xae, 0xc1, 0x0, 0x0, 0x1, 0xdf, 0xc0, 0x0, + 0x0, 0x3, 0xeb, 0x8f, 0x70, 0x18, 0x0, 0xdb, + 0x0, 0x7f, 0x65, 0xf0, 0x3f, 0x40, 0x0, 0x8f, + 0xea, 0x3, 0xf7, 0x0, 0x0, 0xcf, 0x70, 0xb, + 0xf9, 0x66, 0xcf, 0xbf, 0x40, 0x8, 0xdf, 0xea, + 0x30, 0xa5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + + /* U+0027 "'" */ + 0xf5, 0xf5, 0xe4, 0xe4, 0x72, + + /* U+0028 "(" */ + 0x0, 0xda, 0x5, 0xf2, 0xb, 0xc0, 0xf, 0x70, + 0x3f, 0x40, 0x5f, 0x20, 0x6f, 0x10, 0x7f, 0x0, + 0x6f, 0x10, 0x5f, 0x20, 0x3f, 0x40, 0xf, 0x70, + 0xb, 0xc0, 0x5, 0xf2, 0x0, 0xda, + + /* U+0029 ")" */ + 0x3f, 0x30, 0xc, 0xb0, 0x6, 0xf1, 0x1, 0xf6, + 0x0, 0xe9, 0x0, 0xbc, 0x0, 0xad, 0x0, 0xae, + 0x0, 0xad, 0x0, 0xbc, 0x0, 0xe9, 0x1, 0xf6, + 0x6, 0xf1, 0xc, 0xb0, 0x3f, 0x30, + + /* U+002A "*" */ + 0x0, 0x4a, 0x0, 0x6, 0x74, 0xa4, 0xa0, 0x2b, + 0xff, 0xe5, 0x0, 0x7f, 0xfb, 0x20, 0x7b, 0x6b, + 0x8d, 0x0, 0x4, 0xa0, 0x0, 0x0, 0x13, 0x0, + 0x0, + + /* U+002B "+" */ + 0x0, 0x5, 0x10, 0x0, 0x0, 0xf, 0x50, 0x0, + 0x0, 0xf, 0x50, 0x0, 0x1, 0x1f, 0x51, 0x10, + 0xef, 0xff, 0xff, 0xf3, 0x34, 0x4f, 0x74, 0x40, + 0x0, 0xf, 0x50, 0x0, 0x0, 0xf, 0x50, 0x0, + + /* U+002D "-" */ + 0x1, 0x11, 0x10, 0x1f, 0xff, 0xf3, 0x4, 0x44, + 0x40, + + /* U+002E "." */ + 0x3, 0x12, 0xfc, 0x1e, 0x90, + + /* U+002F "/" */ + 0x0, 0x0, 0x5, 0xf1, 0x0, 0x0, 0xa, 0xb0, + 0x0, 0x0, 0xf, 0x60, 0x0, 0x0, 0x5f, 0x10, + 0x0, 0x0, 0xab, 0x0, 0x0, 0x0, 0xf6, 0x0, + 0x0, 0x5, 0xf1, 0x0, 0x0, 0xa, 0xb0, 0x0, + 0x0, 0xf, 0x60, 0x0, 0x0, 0x4f, 0x10, 0x0, + 0x0, 0xac, 0x0, 0x0, 0x0, 0xf6, 0x0, 0x0, + 0x4, 0xf1, 0x0, 0x0, 0xa, 0xc0, 0x0, 0x0, + 0xe, 0x60, 0x0, 0x0, 0x4f, 0x10, 0x0, 0x0, + + /* U+0030 "0" */ + 0x0, 0x8, 0xef, 0xc5, 0x0, 0x0, 0xcf, 0xa8, + 0xcf, 0x70, 0x7, 0xf5, 0x0, 0xa, 0xf2, 0xd, + 0xc0, 0x0, 0x1, 0xf8, 0x1f, 0x80, 0x0, 0x0, + 0xdc, 0x3f, 0x60, 0x0, 0x0, 0xbd, 0x3f, 0x60, + 0x0, 0x0, 0xbd, 0x1f, 0x80, 0x0, 0x0, 0xdc, + 0xd, 0xc0, 0x0, 0x1, 0xf8, 0x7, 0xf5, 0x0, + 0xa, 0xf2, 0x0, 0xcf, 0xa8, 0xcf, 0x70, 0x0, + 0x8, 0xef, 0xc5, 0x0, + + /* U+0031 "1" */ + 0xef, 0xff, 0x36, 0x7a, 0xf3, 0x0, 0x5f, 0x30, + 0x5, 0xf3, 0x0, 0x5f, 0x30, 0x5, 0xf3, 0x0, + 0x5f, 0x30, 0x5, 0xf3, 0x0, 0x5f, 0x30, 0x5, + 0xf3, 0x0, 0x5f, 0x30, 0x5, 0xf3, + + /* U+0032 "2" */ + 0x4, 0xbe, 0xfd, 0x70, 0x7, 0xfd, 0x98, 0xcf, + 0x90, 0x28, 0x0, 0x0, 0xbf, 0x0, 0x0, 0x0, + 0x7, 0xf2, 0x0, 0x0, 0x0, 0xaf, 0x0, 0x0, + 0x0, 0x4f, 0x80, 0x0, 0x0, 0x3f, 0xc0, 0x0, + 0x0, 0x3e, 0xc1, 0x0, 0x0, 0x2e, 0xc1, 0x0, + 0x0, 0x2e, 0xd1, 0x0, 0x0, 0x2e, 0xf8, 0x77, + 0x77, 0x46, 0xff, 0xff, 0xff, 0xfa, + + /* U+0033 "3" */ + 0x6f, 0xff, 0xff, 0xff, 0x2, 0x77, 0x77, 0x9f, + 0xb0, 0x0, 0x0, 0xc, 0xe1, 0x0, 0x0, 0x9, + 0xf3, 0x0, 0x0, 0x5, 0xf6, 0x0, 0x0, 0x0, + 0xdf, 0xe9, 0x10, 0x0, 0x4, 0x59, 0xfd, 0x0, + 0x0, 0x0, 0x6, 0xf4, 0x0, 0x0, 0x0, 0x3f, + 0x64, 0x40, 0x0, 0x8, 0xf3, 0xbf, 0xc9, 0x8c, + 0xfb, 0x0, 0x7c, 0xff, 0xd7, 0x0, + + /* U+0034 "4" */ + 0x0, 0x0, 0x1, 0xeb, 0x0, 0x0, 0x0, 0x0, + 0xbe, 0x10, 0x0, 0x0, 0x0, 0x6f, 0x50, 0x0, + 0x0, 0x0, 0x2f, 0x90, 0x0, 0x0, 0x0, 0xc, + 0xd0, 0x0, 0x0, 0x0, 0x8, 0xf3, 0x1, 0xd5, + 0x0, 0x3, 0xf8, 0x0, 0x2f, 0x60, 0x0, 0xed, + 0x22, 0x23, 0xf7, 0x21, 0x6f, 0xff, 0xff, 0xff, + 0xff, 0x81, 0x55, 0x55, 0x56, 0xf9, 0x52, 0x0, + 0x0, 0x0, 0x2f, 0x60, 0x0, 0x0, 0x0, 0x2, + 0xf6, 0x0, + + /* U+0035 "5" */ + 0x5, 0xff, 0xff, 0xff, 0x0, 0x7f, 0x77, 0x77, + 0x70, 0x8, 0xe0, 0x0, 0x0, 0x0, 0xad, 0x0, + 0x0, 0x0, 0xb, 0xc2, 0x10, 0x0, 0x0, 0xdf, + 0xff, 0xfb, 0x30, 0x4, 0x55, 0x68, 0xff, 0x20, + 0x0, 0x0, 0x4, 0xf8, 0x0, 0x0, 0x0, 0xf, + 0x92, 0x50, 0x0, 0x5, 0xf6, 0x8f, 0xd9, 0x8a, + 0xfd, 0x10, 0x5b, 0xef, 0xe9, 0x10, + + /* U+0036 "6" */ + 0x0, 0x5, 0xce, 0xfc, 0x60, 0x0, 0x9f, 0xc8, + 0x8b, 0x70, 0x5, 0xf8, 0x0, 0x0, 0x0, 0xc, + 0xd0, 0x0, 0x0, 0x0, 0x1f, 0x80, 0x0, 0x0, + 0x0, 0x2f, 0x68, 0xef, 0xfa, 0x10, 0x3f, 0xee, + 0x64, 0x8f, 0xd0, 0x2f, 0xf1, 0x0, 0x6, 0xf4, + 0xe, 0xc0, 0x0, 0x2, 0xf6, 0x9, 0xf1, 0x0, + 0x6, 0xf3, 0x1, 0xde, 0x86, 0x9f, 0xb0, 0x0, + 0x19, 0xef, 0xd8, 0x0, + + /* U+0037 "7" */ + 0x8f, 0xff, 0xff, 0xff, 0xe8, 0xf7, 0x77, 0x77, + 0xfc, 0x8f, 0x0, 0x0, 0x4f, 0x55, 0x90, 0x0, + 0xb, 0xe0, 0x0, 0x0, 0x2, 0xf8, 0x0, 0x0, + 0x0, 0x9f, 0x10, 0x0, 0x0, 0xf, 0xb0, 0x0, + 0x0, 0x6, 0xf4, 0x0, 0x0, 0x0, 0xdd, 0x0, + 0x0, 0x0, 0x3f, 0x70, 0x0, 0x0, 0xa, 0xf1, + 0x0, 0x0, 0x1, 0xf9, 0x0, 0x0, + + /* U+0038 "8" */ + 0x0, 0x5c, 0xff, 0xd7, 0x0, 0x6, 0xfc, 0x76, + 0xaf, 0xa0, 0xc, 0xd0, 0x0, 0x9, 0xf1, 0xd, + 0xc0, 0x0, 0x7, 0xf2, 0x7, 0xf7, 0x11, 0x5e, + 0xc0, 0x0, 0xbf, 0xff, 0xfe, 0x10, 0x9, 0xf9, + 0x54, 0x7e, 0xd0, 0x2f, 0x80, 0x0, 0x4, 0xf6, + 0x4f, 0x50, 0x0, 0x0, 0xf8, 0x1f, 0xa0, 0x0, + 0x5, 0xf6, 0x9, 0xfb, 0x76, 0xaf, 0xd0, 0x0, + 0x6c, 0xff, 0xd8, 0x10, + + /* U+0039 "9" */ + 0x0, 0x8e, 0xfd, 0x80, 0x0, 0xc, 0xf8, 0x68, + 0xfc, 0x0, 0x5f, 0x50, 0x0, 0x3f, 0x70, 0x8f, + 0x0, 0x0, 0xe, 0xc0, 0x7f, 0x30, 0x0, 0x1f, + 0xf0, 0x1f, 0xd4, 0x13, 0xcf, 0xf1, 0x4, 0xef, + 0xff, 0xa9, 0xf0, 0x0, 0x2, 0x31, 0xa, 0xf0, + 0x0, 0x0, 0x0, 0xe, 0xa0, 0x0, 0x0, 0x0, + 0x9f, 0x30, 0x9, 0xa7, 0x8d, 0xf7, 0x0, 0x7, + 0xdf, 0xeb, 0x40, 0x0, + + /* U+003A ":" */ + 0x1e, 0x92, 0xfc, 0x3, 0x10, 0x0, 0x0, 0x0, + 0x0, 0x3, 0x12, 0xfc, 0x1e, 0x90, + + /* U+003B ";" */ + 0x1e, 0x92, 0xfc, 0x3, 0x10, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x1, 0xe9, 0x1f, 0xd0, 0xa8, 0xe, + 0x30, 0xa0, + + /* U+003C "<" */ + 0x0, 0x0, 0x0, 0x42, 0x0, 0x1, 0x7d, 0xf3, + 0x3, 0x9f, 0xe8, 0x10, 0xbf, 0xb5, 0x0, 0x0, + 0xee, 0x81, 0x0, 0x0, 0x17, 0xdf, 0xb4, 0x0, + 0x0, 0x4, 0xaf, 0xd2, 0x0, 0x0, 0x1, 0x82, + + /* U+003D "=" */ + 0xef, 0xff, 0xff, 0xf3, 0x45, 0x55, 0x55, 0x51, + 0x0, 0x0, 0x0, 0x0, 0x1, 0x11, 0x11, 0x10, + 0xef, 0xff, 0xff, 0xf3, 0x34, 0x44, 0x44, 0x40, + + /* U+003E ">" */ + 0x50, 0x0, 0x0, 0x0, 0xef, 0x92, 0x0, 0x0, + 0x6, 0xcf, 0xb5, 0x0, 0x0, 0x3, 0x9f, 0xe2, + 0x0, 0x0, 0x6c, 0xf3, 0x2, 0x9e, 0xe9, 0x20, + 0xbf, 0xc6, 0x0, 0x0, 0x93, 0x0, 0x0, 0x0, + + /* U+003F "?" */ + 0x4, 0xbe, 0xfd, 0x70, 0x7, 0xfc, 0x77, 0xbf, + 0xa0, 0x27, 0x0, 0x0, 0xcf, 0x0, 0x0, 0x0, + 0x9, 0xf0, 0x0, 0x0, 0x1, 0xea, 0x0, 0x0, + 0x1, 0xdd, 0x10, 0x0, 0x0, 0xce, 0x10, 0x0, + 0x0, 0x3f, 0x60, 0x0, 0x0, 0x1, 0x30, 0x0, + 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x6, 0xf5, + 0x0, 0x0, 0x0, 0x5f, 0x40, 0x0, + + /* U+0040 "@" */ + 0x0, 0x0, 0x17, 0xce, 0xfd, 0xb5, 0x0, 0x0, + 0x0, 0x5, 0xfb, 0x53, 0x23, 0x7d, 0xc2, 0x0, + 0x0, 0x6e, 0x40, 0x0, 0x0, 0x0, 0x8e, 0x10, + 0x2, 0xf4, 0x1, 0xae, 0xfa, 0x3f, 0x49, 0xb0, + 0xa, 0x90, 0x1e, 0xe6, 0x5b, 0xef, 0x40, 0xe3, + 0xf, 0x30, 0x8f, 0x10, 0x0, 0xaf, 0x40, 0x98, + 0x1f, 0x0, 0xd9, 0x0, 0x0, 0x3f, 0x40, 0x6a, + 0x3f, 0x0, 0xe8, 0x0, 0x0, 0x1f, 0x40, 0x5c, + 0x1f, 0x0, 0xd9, 0x0, 0x0, 0x3f, 0x40, 0x6a, + 0xf, 0x30, 0x8f, 0x10, 0x0, 0xaf, 0x40, 0x98, + 0xa, 0x90, 0x1e, 0xd6, 0x5a, 0xde, 0xa6, 0xf2, + 0x3, 0xf3, 0x1, 0xaf, 0xfa, 0x16, 0xee, 0x50, + 0x0, 0x6e, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x6, 0xfb, 0x53, 0x23, 0x75, 0x0, 0x0, + 0x0, 0x0, 0x17, 0xce, 0xfd, 0xa3, 0x0, 0x0, + + /* U+0041 "A" */ + 0x0, 0x0, 0x2, 0xfd, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x9f, 0xf4, 0x0, 0x0, 0x0, 0x0, 0xf, + 0x9e, 0xb0, 0x0, 0x0, 0x0, 0x6, 0xf2, 0x7f, + 0x20, 0x0, 0x0, 0x0, 0xdc, 0x1, 0xf8, 0x0, + 0x0, 0x0, 0x4f, 0x60, 0xb, 0xe0, 0x0, 0x0, + 0xb, 0xf0, 0x0, 0x4f, 0x60, 0x0, 0x1, 0xfa, + 0x11, 0x11, 0xed, 0x0, 0x0, 0x8f, 0xff, 0xff, + 0xff, 0xf3, 0x0, 0xe, 0xc4, 0x44, 0x44, 0x4f, + 0xa0, 0x6, 0xf4, 0x0, 0x0, 0x0, 0xaf, 0x10, + 0xcd, 0x0, 0x0, 0x0, 0x2, 0xf8, + + /* U+0042 "B" */ + 0x5f, 0xff, 0xff, 0xeb, 0x40, 0x5, 0xf8, 0x55, + 0x57, 0xdf, 0x40, 0x5f, 0x40, 0x0, 0x1, 0xfa, + 0x5, 0xf4, 0x0, 0x0, 0xf, 0xa0, 0x5f, 0x51, + 0x11, 0x3a, 0xf4, 0x5, 0xff, 0xff, 0xff, 0xfa, + 0x0, 0x5f, 0x74, 0x44, 0x59, 0xfa, 0x5, 0xf4, + 0x0, 0x0, 0x8, 0xf2, 0x5f, 0x40, 0x0, 0x0, + 0x5f, 0x45, 0xf4, 0x0, 0x0, 0x9, 0xf2, 0x5f, + 0x85, 0x55, 0x6a, 0xfb, 0x5, 0xff, 0xff, 0xff, + 0xd7, 0x0, + + /* U+0043 "C" */ + 0x0, 0x2, 0x8d, 0xfe, 0xb4, 0x0, 0x4, 0xff, + 0xb8, 0x9d, 0xf9, 0x2, 0xfd, 0x20, 0x0, 0x8, + 0x50, 0xbf, 0x20, 0x0, 0x0, 0x0, 0xf, 0xa0, + 0x0, 0x0, 0x0, 0x2, 0xf6, 0x0, 0x0, 0x0, + 0x0, 0x2f, 0x60, 0x0, 0x0, 0x0, 0x0, 0xfa, + 0x0, 0x0, 0x0, 0x0, 0xb, 0xf2, 0x0, 0x0, + 0x0, 0x0, 0x2f, 0xd2, 0x0, 0x0, 0x85, 0x0, + 0x5f, 0xfb, 0x89, 0xdf, 0x80, 0x0, 0x29, 0xdf, + 0xeb, 0x40, + + /* U+0044 "D" */ + 0x5f, 0xff, 0xff, 0xea, 0x30, 0x0, 0x5f, 0x97, + 0x77, 0x9e, 0xf8, 0x0, 0x5f, 0x40, 0x0, 0x0, + 0xaf, 0x60, 0x5f, 0x40, 0x0, 0x0, 0xd, 0xe0, + 0x5f, 0x40, 0x0, 0x0, 0x6, 0xf4, 0x5f, 0x40, + 0x0, 0x0, 0x3, 0xf6, 0x5f, 0x40, 0x0, 0x0, + 0x3, 0xf6, 0x5f, 0x40, 0x0, 0x0, 0x6, 0xf4, + 0x5f, 0x40, 0x0, 0x0, 0xd, 0xe0, 0x5f, 0x40, + 0x0, 0x0, 0xaf, 0x60, 0x5f, 0x97, 0x77, 0x9e, + 0xf8, 0x0, 0x5f, 0xff, 0xff, 0xea, 0x30, 0x0, + + /* U+0045 "E" */ + 0x5f, 0xff, 0xff, 0xff, 0x95, 0xf9, 0x77, 0x77, + 0x74, 0x5f, 0x40, 0x0, 0x0, 0x5, 0xf4, 0x0, + 0x0, 0x0, 0x5f, 0x51, 0x11, 0x11, 0x5, 0xff, + 0xff, 0xff, 0xe0, 0x5f, 0x74, 0x44, 0x44, 0x5, + 0xf4, 0x0, 0x0, 0x0, 0x5f, 0x40, 0x0, 0x0, + 0x5, 0xf4, 0x0, 0x0, 0x0, 0x5f, 0x97, 0x77, + 0x77, 0x65, 0xff, 0xff, 0xff, 0xfd, + + /* U+0046 "F" */ + 0x5f, 0xff, 0xff, 0xff, 0x95, 0xf9, 0x77, 0x77, + 0x74, 0x5f, 0x40, 0x0, 0x0, 0x5, 0xf4, 0x0, + 0x0, 0x0, 0x5f, 0x40, 0x0, 0x0, 0x5, 0xf5, + 0x22, 0x22, 0x10, 0x5f, 0xff, 0xff, 0xfe, 0x5, + 0xf8, 0x55, 0x55, 0x40, 0x5f, 0x40, 0x0, 0x0, + 0x5, 0xf4, 0x0, 0x0, 0x0, 0x5f, 0x40, 0x0, + 0x0, 0x5, 0xf4, 0x0, 0x0, 0x0, + + /* U+0047 "G" */ + 0x0, 0x1, 0x8d, 0xfe, 0xb5, 0x0, 0x0, 0x4f, + 0xfb, 0x89, 0xdf, 0xb0, 0x2, 0xfd, 0x20, 0x0, + 0x6, 0x60, 0xb, 0xf2, 0x0, 0x0, 0x0, 0x0, + 0xf, 0xa0, 0x0, 0x0, 0x0, 0x0, 0x2f, 0x60, + 0x0, 0x0, 0x0, 0x0, 0x2f, 0x60, 0x0, 0x0, + 0x9, 0xf0, 0xf, 0xa0, 0x0, 0x0, 0x9, 0xf0, + 0xb, 0xf2, 0x0, 0x0, 0x9, 0xf0, 0x2, 0xfd, + 0x20, 0x0, 0xa, 0xf0, 0x0, 0x4f, 0xfb, 0x89, + 0xdf, 0xc0, 0x0, 0x2, 0x8d, 0xfe, 0xc6, 0x0, + + /* U+0048 "H" */ + 0x5f, 0x40, 0x0, 0x0, 0x4f, 0x55, 0xf4, 0x0, + 0x0, 0x4, 0xf5, 0x5f, 0x40, 0x0, 0x0, 0x4f, + 0x55, 0xf4, 0x0, 0x0, 0x4, 0xf5, 0x5f, 0x52, + 0x22, 0x22, 0x5f, 0x55, 0xff, 0xff, 0xff, 0xff, + 0xf5, 0x5f, 0x85, 0x55, 0x55, 0x8f, 0x55, 0xf4, + 0x0, 0x0, 0x4, 0xf5, 0x5f, 0x40, 0x0, 0x0, + 0x4f, 0x55, 0xf4, 0x0, 0x0, 0x4, 0xf5, 0x5f, + 0x40, 0x0, 0x0, 0x4f, 0x55, 0xf4, 0x0, 0x0, + 0x4, 0xf5, + + /* U+0049 "I" */ + 0x5f, 0x45, 0xf4, 0x5f, 0x45, 0xf4, 0x5f, 0x45, + 0xf4, 0x5f, 0x45, 0xf4, 0x5f, 0x45, 0xf4, 0x5f, + 0x45, 0xf4, + + /* U+004A "J" */ + 0x0, 0xff, 0xff, 0xfa, 0x0, 0x77, 0x77, 0xfa, + 0x0, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0xfa, + 0x0, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0xfa, + 0x0, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0xfa, + 0x0, 0x0, 0x0, 0xf9, 0x7, 0x20, 0x3, 0xf6, + 0xd, 0xe9, 0x8e, 0xf1, 0x1, 0xae, 0xfb, 0x30, + + /* U+004B "K" */ + 0x5f, 0x40, 0x0, 0x2, 0xeb, 0x5, 0xf4, 0x0, + 0x1, 0xec, 0x0, 0x5f, 0x40, 0x1, 0xde, 0x10, + 0x5, 0xf4, 0x0, 0xce, 0x20, 0x0, 0x5f, 0x40, + 0xbf, 0x30, 0x0, 0x5, 0xf4, 0x9f, 0x90, 0x0, + 0x0, 0x5f, 0xcf, 0xef, 0x40, 0x0, 0x5, 0xff, + 0x91, 0xee, 0x10, 0x0, 0x5f, 0xa0, 0x3, 0xfc, + 0x0, 0x5, 0xf4, 0x0, 0x6, 0xf8, 0x0, 0x5f, + 0x40, 0x0, 0x9, 0xf5, 0x5, 0xf4, 0x0, 0x0, + 0xc, 0xf2, + + /* U+004C "L" */ + 0x5f, 0x40, 0x0, 0x0, 0x5, 0xf4, 0x0, 0x0, + 0x0, 0x5f, 0x40, 0x0, 0x0, 0x5, 0xf4, 0x0, + 0x0, 0x0, 0x5f, 0x40, 0x0, 0x0, 0x5, 0xf4, + 0x0, 0x0, 0x0, 0x5f, 0x40, 0x0, 0x0, 0x5, + 0xf4, 0x0, 0x0, 0x0, 0x5f, 0x40, 0x0, 0x0, + 0x5, 0xf4, 0x0, 0x0, 0x0, 0x5f, 0x97, 0x77, + 0x77, 0x25, 0xff, 0xff, 0xff, 0xf5, + + /* U+004D "M" */ + 0x5f, 0x40, 0x0, 0x0, 0x0, 0x1e, 0x95, 0xfc, + 0x0, 0x0, 0x0, 0x8, 0xf9, 0x5f, 0xf5, 0x0, + 0x0, 0x2, 0xff, 0x95, 0xfd, 0xe0, 0x0, 0x0, + 0xae, 0xf9, 0x5f, 0x5f, 0x70, 0x0, 0x3f, 0x5f, + 0x95, 0xf3, 0x8f, 0x10, 0xb, 0xc0, 0xf9, 0x5f, + 0x31, 0xe9, 0x4, 0xf3, 0xf, 0x95, 0xf3, 0x7, + 0xf2, 0xdb, 0x0, 0xf9, 0x5f, 0x30, 0xd, 0xef, + 0x20, 0xf, 0x95, 0xf3, 0x0, 0x5f, 0x90, 0x0, + 0xf9, 0x5f, 0x30, 0x0, 0x71, 0x0, 0xf, 0x95, + 0xf3, 0x0, 0x0, 0x0, 0x0, 0xf9, + + /* U+004E "N" */ + 0x5f, 0x50, 0x0, 0x0, 0x4f, 0x55, 0xff, 0x20, + 0x0, 0x4, 0xf5, 0x5f, 0xfd, 0x0, 0x0, 0x4f, + 0x55, 0xfa, 0xf9, 0x0, 0x4, 0xf5, 0x5f, 0x4a, + 0xf5, 0x0, 0x4f, 0x55, 0xf4, 0xd, 0xf2, 0x4, + 0xf5, 0x5f, 0x40, 0x2f, 0xd0, 0x4f, 0x55, 0xf4, + 0x0, 0x6f, 0x94, 0xf5, 0x5f, 0x40, 0x0, 0xaf, + 0xaf, 0x55, 0xf4, 0x0, 0x0, 0xdf, 0xf5, 0x5f, + 0x40, 0x0, 0x2, 0xff, 0x55, 0xf4, 0x0, 0x0, + 0x6, 0xf5, + + /* U+004F "O" */ + 0x0, 0x1, 0x8d, 0xfe, 0xb5, 0x0, 0x0, 0x4, + 0xff, 0xb8, 0x9e, 0xfa, 0x0, 0x2, 0xfd, 0x20, + 0x0, 0x8, 0xf9, 0x0, 0xbf, 0x20, 0x0, 0x0, + 0xa, 0xf2, 0xf, 0xa0, 0x0, 0x0, 0x0, 0x3f, + 0x72, 0xf6, 0x0, 0x0, 0x0, 0x0, 0xf9, 0x2f, + 0x60, 0x0, 0x0, 0x0, 0xf, 0x90, 0xfa, 0x0, + 0x0, 0x0, 0x3, 0xf7, 0xb, 0xf2, 0x0, 0x0, + 0x0, 0xaf, 0x20, 0x2f, 0xd2, 0x0, 0x0, 0x8f, + 0x90, 0x0, 0x4f, 0xfb, 0x89, 0xef, 0xa0, 0x0, + 0x0, 0x28, 0xdf, 0xeb, 0x50, 0x0, + + /* U+0050 "P" */ + 0x5f, 0xff, 0xff, 0xd7, 0x0, 0x5f, 0x97, 0x78, + 0xbf, 0xc0, 0x5f, 0x40, 0x0, 0x7, 0xf6, 0x5f, + 0x40, 0x0, 0x0, 0xfa, 0x5f, 0x40, 0x0, 0x0, + 0xfa, 0x5f, 0x40, 0x0, 0x3, 0xf8, 0x5f, 0x62, + 0x23, 0x6e, 0xf1, 0x5f, 0xff, 0xff, 0xfd, 0x30, + 0x5f, 0x85, 0x54, 0x20, 0x0, 0x5f, 0x40, 0x0, + 0x0, 0x0, 0x5f, 0x40, 0x0, 0x0, 0x0, 0x5f, + 0x40, 0x0, 0x0, 0x0, + + /* U+0051 "Q" */ + 0x0, 0x1, 0x8d, 0xfe, 0xb5, 0x0, 0x0, 0x0, + 0x4e, 0xfb, 0x89, 0xef, 0xa0, 0x0, 0x2, 0xfd, + 0x20, 0x0, 0x8, 0xf9, 0x0, 0xa, 0xf2, 0x0, + 0x0, 0x0, 0xaf, 0x20, 0xf, 0xa0, 0x0, 0x0, + 0x0, 0x3f, 0x70, 0x2f, 0x60, 0x0, 0x0, 0x0, + 0xf, 0x90, 0x2f, 0x60, 0x0, 0x0, 0x0, 0xf, + 0x90, 0x1f, 0x90, 0x0, 0x0, 0x0, 0x2f, 0x70, + 0xb, 0xf1, 0x0, 0x0, 0x0, 0xaf, 0x20, 0x3, + 0xfc, 0x10, 0x0, 0x7, 0xf9, 0x0, 0x0, 0x6f, + 0xfa, 0x78, 0xdf, 0xb0, 0x0, 0x0, 0x3, 0xae, + 0xff, 0xc5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e, + 0xd4, 0x15, 0xb0, 0x0, 0x0, 0x0, 0x2, 0xbf, + 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, 0x1, 0x31, + 0x0, + + /* U+0052 "R" */ + 0x5f, 0xff, 0xff, 0xd7, 0x0, 0x5f, 0x97, 0x78, + 0xbf, 0xc0, 0x5f, 0x40, 0x0, 0x7, 0xf6, 0x5f, + 0x40, 0x0, 0x0, 0xfa, 0x5f, 0x40, 0x0, 0x0, + 0xfa, 0x5f, 0x40, 0x0, 0x3, 0xf8, 0x5f, 0x52, + 0x23, 0x6e, 0xe1, 0x5f, 0xff, 0xff, 0xfc, 0x30, + 0x5f, 0x85, 0x55, 0xf9, 0x0, 0x5f, 0x40, 0x0, + 0x7f, 0x40, 0x5f, 0x40, 0x0, 0xc, 0xe0, 0x5f, + 0x40, 0x0, 0x2, 0xf9, + + /* U+0053 "S" */ + 0x0, 0x5c, 0xef, 0xd9, 0x20, 0x7, 0xfc, 0x87, + 0xaf, 0x90, 0xe, 0xc0, 0x0, 0x1, 0x10, 0xf, + 0x80, 0x0, 0x0, 0x0, 0xd, 0xf5, 0x0, 0x0, + 0x0, 0x3, 0xef, 0xea, 0x50, 0x0, 0x0, 0x5, + 0xae, 0xfe, 0x40, 0x0, 0x0, 0x0, 0x4e, 0xf1, + 0x0, 0x0, 0x0, 0x5, 0xf3, 0x8, 0x0, 0x0, + 0x8, 0xf2, 0x2f, 0xfa, 0x77, 0xbf, 0xa0, 0x2, + 0x9d, 0xff, 0xc7, 0x0, + + /* U+0054 "T" */ + 0xff, 0xff, 0xff, 0xff, 0xf5, 0x67, 0x78, 0xfb, + 0x77, 0x72, 0x0, 0x1, 0xf7, 0x0, 0x0, 0x0, + 0x1, 0xf7, 0x0, 0x0, 0x0, 0x1, 0xf7, 0x0, + 0x0, 0x0, 0x1, 0xf7, 0x0, 0x0, 0x0, 0x1, + 0xf7, 0x0, 0x0, 0x0, 0x1, 0xf7, 0x0, 0x0, + 0x0, 0x1, 0xf7, 0x0, 0x0, 0x0, 0x1, 0xf7, + 0x0, 0x0, 0x0, 0x1, 0xf7, 0x0, 0x0, 0x0, + 0x1, 0xf7, 0x0, 0x0, + + /* U+0055 "U" */ + 0x6f, 0x30, 0x0, 0x0, 0x8f, 0x16, 0xf3, 0x0, + 0x0, 0x8, 0xf1, 0x6f, 0x30, 0x0, 0x0, 0x8f, + 0x16, 0xf3, 0x0, 0x0, 0x8, 0xf1, 0x6f, 0x30, + 0x0, 0x0, 0x8f, 0x16, 0xf3, 0x0, 0x0, 0x8, + 0xf1, 0x6f, 0x30, 0x0, 0x0, 0x8f, 0x5, 0xf4, + 0x0, 0x0, 0x9, 0xf0, 0x3f, 0x70, 0x0, 0x0, + 0xcd, 0x0, 0xde, 0x20, 0x0, 0x5f, 0x80, 0x4, + 0xff, 0xa8, 0xbf, 0xd0, 0x0, 0x3, 0xbe, 0xfd, + 0x81, 0x0, + + /* U+0056 "V" */ + 0xc, 0xe0, 0x0, 0x0, 0x0, 0x6f, 0x30, 0x6f, + 0x50, 0x0, 0x0, 0xc, 0xc0, 0x0, 0xfb, 0x0, + 0x0, 0x3, 0xf6, 0x0, 0x9, 0xf2, 0x0, 0x0, + 0xae, 0x0, 0x0, 0x2f, 0x80, 0x0, 0x1f, 0x90, + 0x0, 0x0, 0xce, 0x0, 0x7, 0xf2, 0x0, 0x0, + 0x5, 0xf6, 0x0, 0xdb, 0x0, 0x0, 0x0, 0xe, + 0xc0, 0x4f, 0x50, 0x0, 0x0, 0x0, 0x8f, 0x3b, + 0xe0, 0x0, 0x0, 0x0, 0x2, 0xfb, 0xf8, 0x0, + 0x0, 0x0, 0x0, 0xb, 0xff, 0x10, 0x0, 0x0, + 0x0, 0x0, 0x4f, 0xb0, 0x0, 0x0, + + /* U+0057 "W" */ + 0x5f, 0x40, 0x0, 0x0, 0xdf, 0x0, 0x0, 0x2, + 0xf5, 0xf, 0x90, 0x0, 0x2, 0xff, 0x40, 0x0, + 0x7, 0xf0, 0xb, 0xe0, 0x0, 0x7, 0xfe, 0x90, + 0x0, 0xc, 0xb0, 0x6, 0xf3, 0x0, 0xc, 0xaa, + 0xe0, 0x0, 0x1f, 0x60, 0x1, 0xf8, 0x0, 0x1f, + 0x54, 0xf3, 0x0, 0x6f, 0x10, 0x0, 0xcd, 0x0, + 0x7f, 0x10, 0xf8, 0x0, 0xcc, 0x0, 0x0, 0x7f, + 0x20, 0xcb, 0x0, 0xad, 0x1, 0xf7, 0x0, 0x0, + 0x2f, 0x71, 0xf6, 0x0, 0x5f, 0x26, 0xf2, 0x0, + 0x0, 0xd, 0xc6, 0xf1, 0x0, 0xf, 0x7b, 0xd0, + 0x0, 0x0, 0x8, 0xfd, 0xc0, 0x0, 0xb, 0xdf, + 0x80, 0x0, 0x0, 0x3, 0xff, 0x70, 0x0, 0x6, + 0xff, 0x30, 0x0, 0x0, 0x0, 0xef, 0x20, 0x0, + 0x1, 0xfe, 0x0, 0x0, + + /* U+0058 "X" */ + 0x3f, 0x90, 0x0, 0x0, 0xcd, 0x0, 0x8f, 0x40, + 0x0, 0x7f, 0x30, 0x0, 0xde, 0x10, 0x2f, 0x80, + 0x0, 0x3, 0xfa, 0xc, 0xd0, 0x0, 0x0, 0x7, + 0xfb, 0xf3, 0x0, 0x0, 0x0, 0xc, 0xf8, 0x0, + 0x0, 0x0, 0x1, 0xef, 0xc0, 0x0, 0x0, 0x0, + 0xbf, 0x7f, 0x70, 0x0, 0x0, 0x6f, 0x60, 0xaf, + 0x20, 0x0, 0x2f, 0xb0, 0x1, 0xed, 0x0, 0xc, + 0xf1, 0x0, 0x4, 0xf8, 0x7, 0xf6, 0x0, 0x0, + 0x9, 0xf3, + + /* U+0059 "Y" */ + 0xc, 0xe0, 0x0, 0x0, 0x7, 0xf2, 0x3, 0xf7, + 0x0, 0x0, 0x1f, 0x90, 0x0, 0xaf, 0x10, 0x0, + 0x9e, 0x10, 0x0, 0x1f, 0xa0, 0x2, 0xf6, 0x0, + 0x0, 0x8, 0xf3, 0xb, 0xd0, 0x0, 0x0, 0x0, + 0xec, 0x4f, 0x40, 0x0, 0x0, 0x0, 0x5f, 0xfb, + 0x0, 0x0, 0x0, 0x0, 0xc, 0xf2, 0x0, 0x0, + 0x0, 0x0, 0x9, 0xf0, 0x0, 0x0, 0x0, 0x0, + 0x9, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x9, 0xf0, + 0x0, 0x0, 0x0, 0x0, 0x9, 0xf0, 0x0, 0x0, + + /* U+005A "Z" */ + 0x3f, 0xff, 0xff, 0xff, 0xfd, 0x1, 0x77, 0x77, + 0x77, 0xbf, 0x90, 0x0, 0x0, 0x0, 0x1e, 0xc0, + 0x0, 0x0, 0x0, 0xc, 0xf2, 0x0, 0x0, 0x0, + 0x8, 0xf5, 0x0, 0x0, 0x0, 0x4, 0xf9, 0x0, + 0x0, 0x0, 0x1, 0xec, 0x0, 0x0, 0x0, 0x0, + 0xcf, 0x20, 0x0, 0x0, 0x0, 0x8f, 0x50, 0x0, + 0x0, 0x0, 0x4f, 0x90, 0x0, 0x0, 0x0, 0x1e, + 0xf8, 0x77, 0x77, 0x77, 0x5, 0xff, 0xff, 0xff, + 0xff, 0xf0, + + /* U+005B "[" */ + 0x5f, 0xff, 0x5, 0xf7, 0x50, 0x5f, 0x30, 0x5, + 0xf3, 0x0, 0x5f, 0x30, 0x5, 0xf3, 0x0, 0x5f, + 0x30, 0x5, 0xf3, 0x0, 0x5f, 0x30, 0x5, 0xf3, + 0x0, 0x5f, 0x30, 0x5, 0xf3, 0x0, 0x5f, 0x30, + 0x5, 0xf7, 0x50, 0x5f, 0xff, 0x0, + + /* U+005C "\\" */ + 0x7e, 0x0, 0x0, 0x0, 0x1f, 0x40, 0x0, 0x0, + 0xc, 0x90, 0x0, 0x0, 0x7, 0xe0, 0x0, 0x0, + 0x2, 0xf4, 0x0, 0x0, 0x0, 0xc9, 0x0, 0x0, + 0x0, 0x7e, 0x0, 0x0, 0x0, 0x2f, 0x40, 0x0, + 0x0, 0xc, 0x90, 0x0, 0x0, 0x7, 0xe0, 0x0, + 0x0, 0x2, 0xf3, 0x0, 0x0, 0x0, 0xd9, 0x0, + 0x0, 0x0, 0x7e, 0x0, 0x0, 0x0, 0x2f, 0x30, + 0x0, 0x0, 0xd, 0x90, 0x0, 0x0, 0x7, 0xe0, + + /* U+005D "]" */ + 0xbf, 0xfa, 0x35, 0xea, 0x0, 0xea, 0x0, 0xea, + 0x0, 0xea, 0x0, 0xea, 0x0, 0xea, 0x0, 0xea, + 0x0, 0xea, 0x0, 0xea, 0x0, 0xea, 0x0, 0xea, + 0x0, 0xea, 0x35, 0xea, 0xbf, 0xfa, + + /* U+005E "^" */ + 0x0, 0x2f, 0x80, 0x0, 0x0, 0x9d, 0xe0, 0x0, + 0x0, 0xf3, 0xd5, 0x0, 0x6, 0xd0, 0x7b, 0x0, + 0xc, 0x60, 0x1f, 0x20, 0x3f, 0x10, 0xb, 0x80, + 0x9a, 0x0, 0x4, 0xe0, + + /* U+005F "_" */ + 0xff, 0xff, 0xff, 0xff, 0x11, 0x11, 0x11, 0x11, + + /* U+0060 "`" */ + 0x7, 0xf6, 0x0, 0x3, 0xe7, + + /* U+0061 "a" */ + 0x1, 0x9e, 0xfd, 0x80, 0x0, 0xce, 0x87, 0xaf, + 0x90, 0x2, 0x0, 0x0, 0xaf, 0x0, 0x0, 0x0, + 0x6, 0xf2, 0x2, 0xbe, 0xff, 0xff, 0x20, 0xec, + 0x42, 0x27, 0xf2, 0x2f, 0x50, 0x0, 0x7f, 0x20, + 0xec, 0x42, 0x7f, 0xf2, 0x2, 0xbf, 0xfb, 0x6f, + 0x20, + + /* U+0062 "b" */ + 0x8f, 0x0, 0x0, 0x0, 0x0, 0x8f, 0x0, 0x0, + 0x0, 0x0, 0x8f, 0x0, 0x0, 0x0, 0x0, 0x8f, + 0x2b, 0xfe, 0xb3, 0x0, 0x8f, 0xec, 0x78, 0xef, + 0x30, 0x8f, 0xa0, 0x0, 0x1e, 0xc0, 0x8f, 0x20, + 0x0, 0x7, 0xf1, 0x8f, 0x0, 0x0, 0x5, 0xf3, + 0x8f, 0x20, 0x0, 0x7, 0xf1, 0x8f, 0xa0, 0x0, + 0x1e, 0xd0, 0x8f, 0xec, 0x78, 0xef, 0x30, 0x8e, + 0x2b, 0xfe, 0xb3, 0x0, + + /* U+0063 "c" */ + 0x0, 0x3a, 0xef, 0xc4, 0x0, 0x4f, 0xd8, 0x7c, + 0xf4, 0xd, 0xd0, 0x0, 0x7, 0x13, 0xf6, 0x0, + 0x0, 0x0, 0x4f, 0x30, 0x0, 0x0, 0x3, 0xf6, + 0x0, 0x0, 0x0, 0xd, 0xd0, 0x0, 0x6, 0x10, + 0x4f, 0xd7, 0x7c, 0xf4, 0x0, 0x3a, 0xef, 0xc4, + 0x0, + + /* U+0064 "d" */ + 0x0, 0x0, 0x0, 0x1, 0xf7, 0x0, 0x0, 0x0, + 0x1, 0xf7, 0x0, 0x0, 0x0, 0x1, 0xf7, 0x0, + 0x3b, 0xff, 0xa3, 0xf7, 0x4, 0xfd, 0x87, 0xce, + 0xf7, 0xe, 0xd0, 0x0, 0xb, 0xf7, 0x3f, 0x60, + 0x0, 0x3, 0xf7, 0x4f, 0x30, 0x0, 0x1, 0xf7, + 0x3f, 0x50, 0x0, 0x3, 0xf7, 0xe, 0xc0, 0x0, + 0xa, 0xf7, 0x4, 0xfc, 0x65, 0xbe, 0xf7, 0x0, + 0x3b, 0xff, 0xb2, 0xf7, + + /* U+0065 "e" */ + 0x0, 0x3b, 0xfe, 0xa2, 0x0, 0x4, 0xfc, 0x67, + 0xee, 0x20, 0xe, 0xc0, 0x0, 0x1e, 0xa0, 0x3f, + 0x50, 0x0, 0x7, 0xf0, 0x4f, 0xff, 0xff, 0xff, + 0xf1, 0x3f, 0x72, 0x22, 0x22, 0x20, 0xe, 0xc0, + 0x0, 0x2, 0x0, 0x4, 0xfd, 0x87, 0xaf, 0x50, + 0x0, 0x3a, 0xef, 0xd6, 0x0, + + /* U+0066 "f" */ + 0x0, 0x5d, 0xfc, 0x0, 0x2f, 0xb5, 0x70, 0x4, + 0xf3, 0x0, 0xc, 0xff, 0xff, 0xa0, 0x48, 0xf7, + 0x53, 0x0, 0x5f, 0x30, 0x0, 0x5, 0xf3, 0x0, + 0x0, 0x5f, 0x30, 0x0, 0x5, 0xf3, 0x0, 0x0, + 0x5f, 0x30, 0x0, 0x5, 0xf3, 0x0, 0x0, 0x5f, + 0x30, 0x0, + + /* U+0067 "g" */ + 0x0, 0x3b, 0xff, 0xb2, 0xe9, 0x4, 0xfe, 0x87, + 0xcf, 0xf9, 0xe, 0xd1, 0x0, 0xa, 0xf9, 0x3f, + 0x60, 0x0, 0x1, 0xf9, 0x4f, 0x40, 0x0, 0x0, + 0xf9, 0x3f, 0x60, 0x0, 0x1, 0xf9, 0xe, 0xd0, + 0x0, 0x9, 0xf9, 0x4, 0xfd, 0x87, 0xcf, 0xf8, + 0x0, 0x3b, 0xff, 0xb3, 0xf7, 0x0, 0x0, 0x0, + 0x5, 0xf4, 0x9, 0xe9, 0x77, 0xaf, 0xb0, 0x1, + 0x7c, 0xff, 0xd8, 0x0, + + /* U+0068 "h" */ + 0x8f, 0x0, 0x0, 0x0, 0x8, 0xf0, 0x0, 0x0, + 0x0, 0x8f, 0x0, 0x0, 0x0, 0x8, 0xf2, 0xbf, + 0xea, 0x10, 0x8f, 0xfb, 0x89, 0xfd, 0x8, 0xf8, + 0x0, 0x6, 0xf4, 0x8f, 0x10, 0x0, 0x1f, 0x78, + 0xf0, 0x0, 0x0, 0xf8, 0x8f, 0x0, 0x0, 0xf, + 0x88, 0xf0, 0x0, 0x0, 0xf8, 0x8f, 0x0, 0x0, + 0xf, 0x88, 0xf0, 0x0, 0x0, 0xf8, + + /* U+0069 "i" */ + 0x9e, 0x1a, 0xf2, 0x0, 0x8, 0xf0, 0x8f, 0x8, + 0xf0, 0x8f, 0x8, 0xf0, 0x8f, 0x8, 0xf0, 0x8f, + 0x8, 0xf0, + + /* U+006A "j" */ + 0x0, 0x7, 0xe2, 0x0, 0x9, 0xf3, 0x0, 0x0, + 0x0, 0x0, 0x7, 0xf1, 0x0, 0x7, 0xf1, 0x0, + 0x7, 0xf1, 0x0, 0x7, 0xf1, 0x0, 0x7, 0xf1, + 0x0, 0x7, 0xf1, 0x0, 0x7, 0xf1, 0x0, 0x7, + 0xf1, 0x0, 0x7, 0xf1, 0x0, 0x8, 0xf0, 0x18, + 0x6e, 0xc0, 0x3e, 0xfc, 0x20, + + /* U+006B "k" */ + 0x8f, 0x0, 0x0, 0x0, 0x8, 0xf0, 0x0, 0x0, + 0x0, 0x8f, 0x0, 0x0, 0x0, 0x8, 0xf0, 0x0, + 0x1d, 0xd1, 0x8f, 0x0, 0x1d, 0xe2, 0x8, 0xf0, + 0x1d, 0xe2, 0x0, 0x8f, 0x2d, 0xf3, 0x0, 0x8, + 0xfe, 0xff, 0x70, 0x0, 0x8f, 0xe2, 0xbf, 0x30, + 0x8, 0xf2, 0x1, 0xee, 0x10, 0x8f, 0x0, 0x3, + 0xfb, 0x8, 0xf0, 0x0, 0x7, 0xf7, + + /* U+006C "l" */ + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, + + /* U+006D "m" */ + 0x8e, 0x3c, 0xfe, 0x91, 0x3b, 0xfe, 0xa2, 0x8, + 0xff, 0x96, 0x9f, 0xcf, 0xc6, 0x8f, 0xd0, 0x8f, + 0x70, 0x0, 0x9f, 0xc0, 0x0, 0x5f, 0x58, 0xf1, + 0x0, 0x5, 0xf6, 0x0, 0x1, 0xf7, 0x8f, 0x0, + 0x0, 0x4f, 0x40, 0x0, 0xf, 0x88, 0xf0, 0x0, + 0x4, 0xf4, 0x0, 0x0, 0xf8, 0x8f, 0x0, 0x0, + 0x4f, 0x40, 0x0, 0xf, 0x88, 0xf0, 0x0, 0x4, + 0xf4, 0x0, 0x0, 0xf8, 0x8f, 0x0, 0x0, 0x4f, + 0x40, 0x0, 0xf, 0x80, + + /* U+006E "n" */ + 0x8e, 0x3b, 0xfe, 0xa1, 0x8, 0xff, 0xa6, 0x8f, + 0xd0, 0x8f, 0x80, 0x0, 0x6f, 0x48, 0xf1, 0x0, + 0x1, 0xf7, 0x8f, 0x0, 0x0, 0xf, 0x88, 0xf0, + 0x0, 0x0, 0xf8, 0x8f, 0x0, 0x0, 0xf, 0x88, + 0xf0, 0x0, 0x0, 0xf8, 0x8f, 0x0, 0x0, 0xf, + 0x80, + + /* U+006F "o" */ + 0x0, 0x3b, 0xef, 0xc4, 0x0, 0x4, 0xfd, 0x87, + 0xcf, 0x60, 0xe, 0xd0, 0x0, 0xb, 0xf1, 0x3f, + 0x60, 0x0, 0x3, 0xf5, 0x4f, 0x30, 0x0, 0x1, + 0xf7, 0x3f, 0x60, 0x0, 0x3, 0xf5, 0xe, 0xd0, + 0x0, 0xb, 0xf1, 0x4, 0xfd, 0x77, 0xcf, 0x60, + 0x0, 0x3b, 0xef, 0xc4, 0x0, + + /* U+0070 "p" */ + 0x8e, 0x3b, 0xfe, 0xb3, 0x0, 0x8f, 0xfb, 0x57, + 0xdf, 0x30, 0x8f, 0x90, 0x0, 0xd, 0xc0, 0x8f, + 0x10, 0x0, 0x7, 0xf1, 0x8f, 0x0, 0x0, 0x5, + 0xf3, 0x8f, 0x20, 0x0, 0x7, 0xf1, 0x8f, 0xa0, + 0x0, 0x1e, 0xd0, 0x8f, 0xec, 0x78, 0xef, 0x30, + 0x8f, 0x2b, 0xfe, 0xb3, 0x0, 0x8f, 0x0, 0x0, + 0x0, 0x0, 0x8f, 0x0, 0x0, 0x0, 0x0, 0x8f, + 0x0, 0x0, 0x0, 0x0, + + /* U+0071 "q" */ + 0x0, 0x3b, 0xff, 0xa2, 0xf7, 0x4, 0xfd, 0x87, + 0xde, 0xf7, 0xe, 0xd0, 0x0, 0xb, 0xf7, 0x3f, + 0x60, 0x0, 0x3, 0xf7, 0x4f, 0x30, 0x0, 0x1, + 0xf7, 0x3f, 0x60, 0x0, 0x3, 0xf7, 0xe, 0xd0, + 0x0, 0xb, 0xf7, 0x4, 0xfd, 0x77, 0xce, 0xf7, + 0x0, 0x3b, 0xff, 0xa3, 0xf7, 0x0, 0x0, 0x0, + 0x1, 0xf7, 0x0, 0x0, 0x0, 0x1, 0xf7, 0x0, + 0x0, 0x0, 0x1, 0xf7, + + /* U+0072 "r" */ + 0x8e, 0x2b, 0xf0, 0x8f, 0xed, 0x90, 0x8f, 0xa0, + 0x0, 0x8f, 0x20, 0x0, 0x8f, 0x0, 0x0, 0x8f, + 0x0, 0x0, 0x8f, 0x0, 0x0, 0x8f, 0x0, 0x0, + 0x8f, 0x0, 0x0, + + /* U+0073 "s" */ + 0x2, 0xae, 0xfd, 0x91, 0x1e, 0xd7, 0x69, 0xd0, + 0x4f, 0x30, 0x0, 0x0, 0x2f, 0xb4, 0x10, 0x0, + 0x6, 0xef, 0xfd, 0x60, 0x0, 0x1, 0x5b, 0xf5, + 0x1, 0x0, 0x0, 0xf7, 0x5f, 0xa7, 0x6b, 0xf3, + 0x19, 0xdf, 0xec, 0x40, + + /* U+0074 "t" */ + 0x5, 0xf3, 0x0, 0x0, 0x5f, 0x30, 0x0, 0xcf, + 0xff, 0xfa, 0x4, 0x8f, 0x75, 0x30, 0x5, 0xf3, + 0x0, 0x0, 0x5f, 0x30, 0x0, 0x5, 0xf3, 0x0, + 0x0, 0x5f, 0x30, 0x0, 0x4, 0xf4, 0x0, 0x0, + 0x1f, 0xc6, 0x80, 0x0, 0x5d, 0xfc, 0x10, + + /* U+0075 "u" */ + 0xae, 0x0, 0x0, 0x2f, 0x5a, 0xe0, 0x0, 0x2, + 0xf5, 0xae, 0x0, 0x0, 0x2f, 0x5a, 0xe0, 0x0, + 0x2, 0xf5, 0xae, 0x0, 0x0, 0x2f, 0x59, 0xf0, + 0x0, 0x4, 0xf5, 0x6f, 0x30, 0x0, 0xaf, 0x51, + 0xee, 0x76, 0xbf, 0xf5, 0x2, 0xbe, 0xfb, 0x3f, + 0x50, + + /* U+0076 "v" */ + 0xd, 0xc0, 0x0, 0x0, 0xcb, 0x6, 0xf2, 0x0, + 0x2, 0xf5, 0x0, 0xf9, 0x0, 0x9, 0xe0, 0x0, + 0x9e, 0x0, 0xf, 0x80, 0x0, 0x2f, 0x60, 0x6f, + 0x10, 0x0, 0xc, 0xc0, 0xcb, 0x0, 0x0, 0x5, + 0xf6, 0xf4, 0x0, 0x0, 0x0, 0xef, 0xd0, 0x0, + 0x0, 0x0, 0x8f, 0x70, 0x0, + + /* U+0077 "w" */ + 0xbb, 0x0, 0x0, 0x9f, 0x10, 0x0, 0x4f, 0x16, + 0xf1, 0x0, 0xe, 0xf6, 0x0, 0x9, 0xc0, 0xf, + 0x60, 0x5, 0xfc, 0xb0, 0x0, 0xf6, 0x0, 0xac, + 0x0, 0xab, 0x5f, 0x10, 0x5f, 0x10, 0x5, 0xf1, + 0xf, 0x50, 0xf7, 0xa, 0xb0, 0x0, 0xf, 0x76, + 0xf0, 0x9, 0xc0, 0xf5, 0x0, 0x0, 0xac, 0xba, + 0x0, 0x4f, 0x8f, 0x0, 0x0, 0x4, 0xff, 0x40, + 0x0, 0xef, 0xa0, 0x0, 0x0, 0xe, 0xe0, 0x0, + 0x8, 0xf4, 0x0, 0x0, + + /* U+0078 "x" */ + 0x4f, 0x70, 0x0, 0x9f, 0x20, 0x8f, 0x30, 0x5f, + 0x50, 0x0, 0xcd, 0x2e, 0x90, 0x0, 0x2, 0xff, + 0xd0, 0x0, 0x0, 0xa, 0xf6, 0x0, 0x0, 0x4, + 0xfd, 0xe1, 0x0, 0x1, 0xeb, 0xd, 0xc0, 0x0, + 0xbe, 0x10, 0x3f, 0x80, 0x6f, 0x40, 0x0, 0x7f, + 0x40, + + /* U+0079 "y" */ + 0xd, 0xc0, 0x0, 0x0, 0xcb, 0x6, 0xf3, 0x0, + 0x2, 0xf4, 0x0, 0xea, 0x0, 0x9, 0xd0, 0x0, + 0x8f, 0x10, 0x1f, 0x70, 0x0, 0x1f, 0x70, 0x7f, + 0x10, 0x0, 0xa, 0xe0, 0xd9, 0x0, 0x0, 0x3, + 0xf9, 0xf2, 0x0, 0x0, 0x0, 0xcf, 0xb0, 0x0, + 0x0, 0x0, 0x6f, 0x40, 0x0, 0x0, 0x0, 0xad, + 0x0, 0x0, 0x1c, 0x79, 0xf5, 0x0, 0x0, 0x1a, + 0xee, 0x70, 0x0, 0x0, + + /* U+007A "z" */ + 0x4f, 0xff, 0xff, 0xf9, 0x15, 0x55, 0x5b, 0xf4, + 0x0, 0x0, 0x4f, 0x80, 0x0, 0x1, 0xec, 0x0, + 0x0, 0xb, 0xe1, 0x0, 0x0, 0x8f, 0x40, 0x0, + 0x4, 0xf7, 0x0, 0x0, 0x1e, 0xe5, 0x55, 0x53, + 0x5f, 0xff, 0xff, 0xfc, + + /* U+007B "{" */ + 0x0, 0x2c, 0xf5, 0x0, 0xaf, 0x61, 0x0, 0xcc, + 0x0, 0x0, 0xdb, 0x0, 0x0, 0xdb, 0x0, 0x0, + 0xdb, 0x0, 0x2, 0xea, 0x0, 0x1f, 0xf4, 0x0, + 0x5, 0xfa, 0x0, 0x0, 0xdb, 0x0, 0x0, 0xdb, + 0x0, 0x0, 0xdb, 0x0, 0x0, 0xcc, 0x0, 0x0, + 0xaf, 0x61, 0x0, 0x2c, 0xf5, + + /* U+007C "|" */ + 0x5f, 0x15, 0xf1, 0x5f, 0x15, 0xf1, 0x5f, 0x15, + 0xf1, 0x5f, 0x15, 0xf1, 0x5f, 0x15, 0xf1, 0x5f, + 0x15, 0xf1, 0x5f, 0x15, 0xf1, 0x5f, 0x10, + + /* U+007D "}" */ + 0xbe, 0x80, 0x3, 0xaf, 0x40, 0x1, 0xf6, 0x0, + 0x1f, 0x70, 0x1, 0xf7, 0x0, 0x1f, 0x70, 0x0, + 0xf9, 0x0, 0xa, 0xfb, 0x0, 0xfb, 0x20, 0x1f, + 0x70, 0x1, 0xf7, 0x0, 0x1f, 0x70, 0x1, 0xf6, + 0x3, 0xaf, 0x40, 0xbe, 0x90, 0x0, + + /* U+007E "~" */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x3d, 0xe4, 0x0, + 0xb5, 0xc, 0x86, 0xf5, 0x1e, 0x20, 0xf0, 0x3, + 0xef, 0x90, 0x2, 0x0, 0x0, 0x10, 0x0, + + /* U+F001 "" */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x49, 0xdc, + 0x0, 0x0, 0x0, 0x0, 0x16, 0xbf, 0xff, 0xff, + 0x0, 0x0, 0x3, 0x8d, 0xff, 0xff, 0xff, 0xff, + 0x0, 0x0, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0xff, + 0x0, 0x0, 0xff, 0xff, 0xea, 0x51, 0x0, 0xff, + 0x0, 0x0, 0xff, 0x83, 0x0, 0x0, 0x0, 0xff, + 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, + 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, + 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0xff, + 0x0, 0x0, 0xff, 0x0, 0x0, 0x2b, 0xff, 0xff, + 0x0, 0x0, 0xff, 0x0, 0x0, 0xdf, 0xff, 0xff, + 0x2b, 0xff, 0xff, 0x0, 0x0, 0xdf, 0xff, 0xfd, + 0xdf, 0xff, 0xff, 0x0, 0x0, 0x2b, 0xff, 0xb2, + 0xdf, 0xff, 0xfd, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x2b, 0xff, 0xb2, 0x0, 0x0, 0x0, 0x0, 0x0, + + /* U+F008 "" */ + 0xd0, 0xf, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xd, + 0xff, 0xff, 0xc8, 0x88, 0x88, 0x8c, 0xff, 0xff, + 0xf0, 0xf, 0x80, 0x0, 0x0, 0x8, 0xf0, 0xf, + 0xf0, 0xf, 0x80, 0x0, 0x0, 0x8, 0xf0, 0xf, + 0xff, 0xff, 0x80, 0x0, 0x0, 0x8, 0xff, 0xff, + 0xf0, 0xf, 0xec, 0xcc, 0xcc, 0xce, 0xf0, 0xf, + 0xf0, 0xf, 0xec, 0xcc, 0xcc, 0xce, 0xf0, 0xf, + 0xff, 0xff, 0x80, 0x0, 0x0, 0x8, 0xff, 0xff, + 0xf0, 0xf, 0x80, 0x0, 0x0, 0x8, 0xf0, 0xf, + 0xf0, 0xf, 0x80, 0x0, 0x0, 0x8, 0xf0, 0xf, + 0xff, 0xff, 0xc8, 0x88, 0x88, 0x8c, 0xff, 0xff, + 0xd0, 0xf, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xd, + + /* U+F00B "" */ + 0xdf, 0xff, 0x73, 0xff, 0xff, 0xff, 0xff, 0xfd, + 0xff, 0xff, 0xa5, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xa5, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xdf, 0xff, 0x73, 0xff, 0xff, 0xff, 0xff, 0xfd, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xdf, 0xff, 0x73, 0xff, 0xff, 0xff, 0xff, 0xfd, + 0xff, 0xff, 0xa5, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xa5, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xdf, 0xff, 0x73, 0xff, 0xff, 0xff, 0xff, 0xfd, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xdf, 0xff, 0x73, 0xff, 0xff, 0xff, 0xff, 0xfd, + 0xff, 0xff, 0xa5, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xa5, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xdf, 0xff, 0x73, 0xff, 0xff, 0xff, 0xff, 0xfd, + + /* U+F00C "" */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0xb1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xfc, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xff, 0xfb, + 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xff, 0xc0, + 0x1b, 0xa0, 0x0, 0x0, 0xb, 0xff, 0xfc, 0x0, + 0xcf, 0xfb, 0x0, 0x0, 0xbf, 0xff, 0xc0, 0x0, + 0xbf, 0xff, 0xb0, 0xb, 0xff, 0xfc, 0x0, 0x0, + 0xc, 0xff, 0xfb, 0xbf, 0xff, 0xc0, 0x0, 0x0, + 0x0, 0xcf, 0xff, 0xff, 0xfb, 0x0, 0x0, 0x0, + 0x0, 0xc, 0xff, 0xff, 0xb0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xbf, 0xfb, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xb, 0xb0, 0x0, 0x0, 0x0, 0x0, + + /* U+F00D "" */ + 0x3, 0x0, 0x0, 0x0, 0x3, 0x8, 0xfc, 0x10, + 0x0, 0x1c, 0xf8, 0xff, 0xfc, 0x10, 0x1c, 0xff, + 0xf5, 0xff, 0xfc, 0x2c, 0xff, 0xf5, 0x5, 0xff, + 0xff, 0xff, 0xf5, 0x0, 0x5, 0xff, 0xff, 0xf5, + 0x0, 0x0, 0x1d, 0xff, 0xfd, 0x10, 0x0, 0x1c, + 0xff, 0xff, 0xfc, 0x10, 0x1c, 0xff, 0xf9, 0xff, + 0xfc, 0x1c, 0xff, 0xf5, 0x5, 0xff, 0xfc, 0xdf, + 0xf5, 0x0, 0x5, 0xff, 0xd1, 0xa4, 0x0, 0x0, + 0x4, 0xa1, + + /* U+F011 "" */ + 0x0, 0x0, 0x0, 0x4f, 0xe0, 0x0, 0x0, 0x0, + 0x0, 0x2, 0x10, 0x6f, 0xf1, 0x3, 0x10, 0x0, + 0x0, 0x5f, 0xd0, 0x6f, 0xf1, 0x3f, 0xd1, 0x0, + 0x3, 0xff, 0xf1, 0x6f, 0xf1, 0x5f, 0xfd, 0x0, + 0xd, 0xff, 0x40, 0x6f, 0xf1, 0x9, 0xff, 0x70, + 0x4f, 0xf7, 0x0, 0x6f, 0xf1, 0x0, 0xcf, 0xe0, + 0x9f, 0xf0, 0x0, 0x6f, 0xf1, 0x0, 0x5f, 0xf3, + 0xbf, 0xc0, 0x0, 0x6f, 0xf1, 0x0, 0x2f, 0xf5, + 0xbf, 0xc0, 0x0, 0x4f, 0xe0, 0x0, 0x1f, 0xf6, + 0xaf, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x4f, 0xf4, + 0x6f, 0xf4, 0x0, 0x0, 0x0, 0x0, 0xaf, 0xf0, + 0xf, 0xfe, 0x10, 0x0, 0x0, 0x5, 0xff, 0xa0, + 0x6, 0xff, 0xd3, 0x0, 0x0, 0x7f, 0xff, 0x20, + 0x0, 0x9f, 0xff, 0xda, 0xbe, 0xff, 0xf4, 0x0, + 0x0, 0x6, 0xff, 0xff, 0xff, 0xfd, 0x30, 0x0, + 0x0, 0x0, 0x17, 0xbd, 0xca, 0x50, 0x0, 0x0, + + /* U+F013 "" */ + 0x0, 0x0, 0x0, 0x8b, 0xb8, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, + 0x0, 0x30, 0x6, 0xff, 0xff, 0x60, 0x3, 0x0, + 0x4, 0xfd, 0xdf, 0xff, 0xff, 0xfd, 0xef, 0x40, + 0xd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd0, + 0x4f, 0xff, 0xff, 0xf9, 0x9f, 0xff, 0xff, 0xf4, + 0x8, 0xff, 0xff, 0x20, 0x2, 0xff, 0xff, 0x80, + 0x0, 0xff, 0xf9, 0x0, 0x0, 0x9f, 0xff, 0x0, + 0x0, 0xff, 0xf9, 0x0, 0x0, 0x9f, 0xff, 0x0, + 0x8, 0xff, 0xff, 0x20, 0x2, 0xff, 0xff, 0x80, + 0x4f, 0xff, 0xff, 0xf9, 0x9f, 0xff, 0xff, 0xf4, + 0xd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd0, + 0x4, 0xfe, 0xdf, 0xff, 0xff, 0xfd, 0xdf, 0x40, + 0x0, 0x30, 0x6, 0xff, 0xff, 0x60, 0x3, 0x0, + 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x8b, 0xb8, 0x0, 0x0, 0x0, + + /* U+F015 "" */ + 0x0, 0x0, 0x0, 0x3, 0xdd, 0x30, 0x3f, 0xf3, + 0x0, 0x0, 0x0, 0x0, 0x6f, 0xff, 0xf5, 0x4f, + 0xf4, 0x0, 0x0, 0x0, 0x9, 0xff, 0x99, 0xff, + 0xbf, 0xf4, 0x0, 0x0, 0x1, 0xbf, 0xf6, 0x22, + 0x6f, 0xff, 0xf4, 0x0, 0x0, 0x2d, 0xfe, 0x35, + 0xff, 0x53, 0xef, 0xf4, 0x0, 0x4, 0xff, 0xc1, + 0x8f, 0xff, 0xf8, 0x2d, 0xfe, 0x40, 0x7f, 0xfa, + 0x1a, 0xff, 0xff, 0xff, 0xa1, 0xaf, 0xf7, 0xcf, + 0x82, 0xdf, 0xff, 0xff, 0xff, 0xfd, 0x28, 0xfc, + 0x14, 0xe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, + 0x41, 0x0, 0xf, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf0, 0x0, 0x0, 0xf, 0xff, 0xf9, 0x0, 0x8f, + 0xff, 0xf0, 0x0, 0x0, 0xf, 0xff, 0xf8, 0x0, + 0x8f, 0xff, 0xf0, 0x0, 0x0, 0xf, 0xff, 0xf8, + 0x0, 0x8f, 0xff, 0xf0, 0x0, 0x0, 0xe, 0xff, + 0xf6, 0x0, 0x6f, 0xff, 0xe0, 0x0, + + /* U+F019 "" */ + 0x0, 0x0, 0x0, 0xdf, 0xfd, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, + 0x0, 0x4f, 0xff, 0xff, 0xff, 0xff, 0xf4, 0x0, + 0x0, 0xb, 0xff, 0xff, 0xff, 0xff, 0xb0, 0x0, + 0x0, 0x0, 0xbf, 0xff, 0xff, 0xfb, 0x0, 0x0, + 0x0, 0x0, 0xb, 0xff, 0xff, 0xb0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xbf, 0xfb, 0x0, 0x0, 0x0, + 0xdf, 0xff, 0xfc, 0x1b, 0xb1, 0xcf, 0xff, 0xfd, + 0xff, 0xff, 0xff, 0xc2, 0x2c, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xe0, 0xff, + 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, + + /* U+F01C "" */ + 0x0, 0x4, 0xef, 0xff, 0xff, 0xff, 0xfe, 0x40, + 0x0, 0x0, 0x1e, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xe1, 0x0, 0x0, 0xaf, 0xb0, 0x0, 0x0, 0x0, + 0xb, 0xfa, 0x0, 0x5, 0xff, 0x10, 0x0, 0x0, + 0x0, 0x1, 0xff, 0x50, 0x1e, 0xf6, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x6f, 0xe1, 0xaf, 0xb0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xb, 0xfa, 0xff, 0xff, + 0xff, 0x80, 0x0, 0x8, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xf1, 0x0, 0x1f, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x8f, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xf8, + + /* U+F021 "" */ + 0x0, 0x0, 0x6, 0xbd, 0xda, 0x50, 0x2, 0xff, + 0x0, 0x5, 0xef, 0xff, 0xff, 0xfe, 0x42, 0xff, + 0x0, 0x7f, 0xff, 0xa7, 0x7b, 0xff, 0xf9, 0xff, + 0x5, 0xff, 0xc1, 0x0, 0x0, 0x2c, 0xff, 0xff, + 0xe, 0xfc, 0x0, 0x0, 0x2, 0x22, 0xdf, 0xff, + 0x5f, 0xf2, 0x0, 0x0, 0xf, 0xff, 0xff, 0xff, + 0x8f, 0xb0, 0x0, 0x0, 0xf, 0xff, 0xff, 0xff, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xff, 0xff, 0xff, 0xf0, 0x0, 0x0, 0xb, 0xf8, + 0xff, 0xff, 0xff, 0xf0, 0x0, 0x0, 0x2f, 0xf4, + 0xff, 0xfd, 0x22, 0x20, 0x0, 0x0, 0xcf, 0xe0, + 0xff, 0xff, 0xc2, 0x0, 0x0, 0x2c, 0xff, 0x40, + 0xff, 0x9f, 0xff, 0xb7, 0x6a, 0xff, 0xf7, 0x0, + 0xff, 0x24, 0xdf, 0xff, 0xff, 0xfe, 0x50, 0x0, + 0xff, 0x20, 0x5, 0xac, 0xdb, 0x60, 0x0, 0x0, + + /* U+F026 "" */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8d, + 0x0, 0x0, 0x8, 0xff, 0x0, 0x0, 0x8f, 0xff, + 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, + 0x0, 0x0, 0x8f, 0xff, 0x0, 0x0, 0x8, 0xff, + 0x0, 0x0, 0x0, 0x8d, 0x0, 0x0, 0x0, 0x0, + + /* U+F027 "" */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x8d, 0x0, 0x0, 0x0, 0x0, 0x8, 0xff, + 0x0, 0x0, 0x0, 0x0, 0x8f, 0xff, 0x0, 0x0, + 0xcf, 0xff, 0xff, 0xff, 0x1, 0x50, 0xff, 0xff, + 0xff, 0xff, 0x6, 0xf7, 0xff, 0xff, 0xff, 0xff, + 0x0, 0xbe, 0xff, 0xff, 0xff, 0xff, 0x0, 0xae, + 0xff, 0xff, 0xff, 0xff, 0x5, 0xf8, 0xdf, 0xff, + 0xff, 0xff, 0x2, 0x60, 0x0, 0x0, 0x9f, 0xff, + 0x0, 0x0, 0x0, 0x0, 0x9, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x9e, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, + + /* U+F028 "" */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0x10, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, + 0xd2, 0x0, 0x0, 0x0, 0x0, 0x8d, 0x0, 0x0, + 0x3, 0xee, 0x10, 0x0, 0x0, 0x8, 0xff, 0x0, + 0xa, 0xb1, 0x2f, 0xb0, 0x0, 0x0, 0x8f, 0xff, + 0x0, 0x5, 0xfc, 0x7, 0xf4, 0xdf, 0xff, 0xff, + 0xff, 0x2, 0x50, 0x5f, 0x60, 0xf9, 0xff, 0xff, + 0xff, 0xff, 0x6, 0xf7, 0xd, 0xc0, 0xbd, 0xff, + 0xff, 0xff, 0xff, 0x0, 0xae, 0x9, 0xf0, 0x9f, + 0xff, 0xff, 0xff, 0xff, 0x0, 0xae, 0x9, 0xf0, + 0x8f, 0xff, 0xff, 0xff, 0xff, 0x6, 0xf7, 0xd, + 0xc0, 0xad, 0xdf, 0xff, 0xff, 0xff, 0x2, 0x50, + 0x5f, 0x60, 0xe9, 0x0, 0x0, 0x8f, 0xff, 0x0, + 0x5, 0xfc, 0x6, 0xf4, 0x0, 0x0, 0x8, 0xff, + 0x0, 0xa, 0xb1, 0x2f, 0xb0, 0x0, 0x0, 0x0, + 0x8d, 0x0, 0x0, 0x2, 0xee, 0x10, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x1f, 0xd2, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0x10, 0x0, + + /* U+F03E "" */ + 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, + 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x20, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfc, 0x0, 0xc, 0xff, 0xff, 0xee, 0xff, 0xff, + 0xff, 0x20, 0x2f, 0xff, 0xfe, 0x22, 0xef, 0xff, + 0xff, 0xfc, 0xff, 0xff, 0xe2, 0x0, 0x2e, 0xff, + 0xff, 0xfe, 0x4e, 0xfe, 0x20, 0x0, 0x2, 0xff, + 0xff, 0xe2, 0x2, 0xc2, 0x0, 0x0, 0x0, 0xff, + 0xff, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, + 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, + + /* U+F048 "" */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x30, 0x0, + 0x1, 0xcc, 0xff, 0x40, 0x0, 0x2d, 0xff, 0xff, + 0x40, 0x3, 0xef, 0xff, 0xff, 0x40, 0x3f, 0xff, + 0xff, 0xff, 0x44, 0xff, 0xff, 0xff, 0xff, 0x9f, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xaf, 0xff, + 0xff, 0xff, 0xff, 0x45, 0xff, 0xff, 0xff, 0xff, + 0x40, 0x4f, 0xff, 0xff, 0xff, 0x40, 0x3, 0xef, + 0xff, 0xff, 0x40, 0x0, 0x2e, 0xff, 0xff, 0x30, + 0x0, 0x1, 0xcc, 0x0, 0x0, 0x0, 0x0, 0x0, + + /* U+F04B "" */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8f, + 0x91, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, + 0x70, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xfd, + 0x40, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xfa, + 0x10, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xf7, + 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd5, + 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb2, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xb2, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xd5, 0x0, 0xff, 0xff, 0xff, 0xff, + 0xf7, 0x0, 0x0, 0xff, 0xff, 0xff, 0xfa, 0x10, + 0x0, 0x0, 0xff, 0xff, 0xfd, 0x40, 0x0, 0x0, + 0x0, 0xff, 0xff, 0x70, 0x0, 0x0, 0x0, 0x0, + 0x8e, 0xa1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + + /* U+F04C "" */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8f, + 0xff, 0xf8, 0x0, 0x8f, 0xff, 0xf8, 0xff, 0xff, + 0xff, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x0, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x0, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0xff, + 0xff, 0xff, 0x7f, 0xff, 0xf7, 0x0, 0x7f, 0xff, + 0xf7, + + /* U+F04D "" */ + 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x8f, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xf8, + + /* U+F051 "" */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0xcc, 0x10, 0x0, + 0x3, 0xff, 0xff, 0xd2, 0x0, 0x4, 0xff, 0xff, + 0xfe, 0x30, 0x4, 0xff, 0xff, 0xff, 0xf4, 0x4, + 0xff, 0xff, 0xff, 0xff, 0x54, 0xff, 0xff, 0xff, + 0xff, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf9, 0xff, 0xff, 0xff, 0xff, 0x44, 0xff, 0xff, + 0xff, 0xf3, 0x4, 0xff, 0xff, 0xfe, 0x30, 0x4, + 0xff, 0xff, 0xd2, 0x0, 0x4, 0xff, 0xcc, 0x10, + 0x0, 0x3, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, + + /* U+F052 "" */ + 0x0, 0x0, 0x0, 0x2d, 0xd2, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x1, 0xef, 0xfe, 0x10, 0x0, 0x0, + 0x0, 0x0, 0x1d, 0xff, 0xff, 0xd1, 0x0, 0x0, + 0x0, 0x0, 0xcf, 0xff, 0xff, 0xfc, 0x0, 0x0, + 0x0, 0xb, 0xff, 0xff, 0xff, 0xff, 0xb0, 0x0, + 0x0, 0xaf, 0xff, 0xff, 0xff, 0xff, 0xfa, 0x0, + 0x9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x90, + 0xf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0x8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0xf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0xc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + + /* U+F053 "" */ + 0x0, 0x0, 0x0, 0x1a, 0x40, 0x0, 0x0, 0x1, + 0xdf, 0xf0, 0x0, 0x0, 0x1d, 0xff, 0xa0, 0x0, + 0x1, 0xdf, 0xfa, 0x0, 0x0, 0x1d, 0xff, 0xa0, + 0x0, 0x1, 0xdf, 0xfa, 0x0, 0x0, 0xc, 0xff, + 0xa0, 0x0, 0x0, 0xd, 0xff, 0x80, 0x0, 0x0, + 0x1, 0xdf, 0xf8, 0x0, 0x0, 0x0, 0x1d, 0xff, + 0x80, 0x0, 0x0, 0x1, 0xdf, 0xf8, 0x0, 0x0, + 0x0, 0x1d, 0xff, 0x80, 0x0, 0x0, 0x1, 0xdf, + 0xf0, 0x0, 0x0, 0x0, 0x1b, 0x50, + + /* U+F054 "" */ + 0x4, 0xa1, 0x0, 0x0, 0x0, 0xf, 0xfd, 0x10, + 0x0, 0x0, 0xa, 0xff, 0xd1, 0x0, 0x0, 0x0, + 0xaf, 0xfd, 0x10, 0x0, 0x0, 0xa, 0xff, 0xd1, + 0x0, 0x0, 0x0, 0xaf, 0xfd, 0x10, 0x0, 0x0, + 0xa, 0xff, 0xc0, 0x0, 0x0, 0x8, 0xff, 0xd0, + 0x0, 0x0, 0x8f, 0xfd, 0x10, 0x0, 0x8, 0xff, + 0xd1, 0x0, 0x0, 0x8f, 0xfd, 0x10, 0x0, 0x8, + 0xff, 0xd1, 0x0, 0x0, 0xf, 0xfd, 0x10, 0x0, + 0x0, 0x5, 0xb1, 0x0, 0x0, 0x0, + + /* U+F067 "" */ + 0x0, 0x0, 0x4, 0xff, 0x40, 0x0, 0x0, 0x0, + 0x0, 0x8, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, + 0x8, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, 0x8, + 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, 0x8, 0xff, + 0x80, 0x0, 0x0, 0x48, 0x88, 0x8c, 0xff, 0xc8, + 0x88, 0x84, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x48, 0x88, 0x8c, 0xff, 0xc8, 0x88, 0x84, 0x0, + 0x0, 0x8, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, + 0x8, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, 0x8, + 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, 0x8, 0xff, + 0x80, 0x0, 0x0, 0x0, 0x0, 0x4, 0xff, 0x40, + 0x0, 0x0, + + /* U+F068 "" */ + 0x14, 0x44, 0x44, 0x44, 0x44, 0x44, 0x41, 0xef, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x7b, 0xbb, 0xbb, + 0xbb, 0xbb, 0xbb, 0xb7, + + /* U+F06E "" */ + 0x0, 0x0, 0x5, 0xad, 0xff, 0xda, 0x50, 0x0, + 0x0, 0x0, 0x4, 0xdf, 0xfc, 0x88, 0xcf, 0xfd, + 0x40, 0x0, 0x0, 0x7f, 0xfe, 0x40, 0x0, 0x4, + 0xef, 0xf7, 0x0, 0x7, 0xff, 0xf4, 0x0, 0x9e, + 0x80, 0x4f, 0xff, 0x70, 0x4f, 0xff, 0xc0, 0x0, + 0xaf, 0xf8, 0xc, 0xff, 0xf4, 0xdf, 0xff, 0x80, + 0x9a, 0xff, 0xfe, 0x8, 0xff, 0xfd, 0xdf, 0xff, + 0x80, 0xef, 0xff, 0xfe, 0x8, 0xff, 0xfd, 0x4f, + 0xff, 0xc0, 0x8f, 0xff, 0xf8, 0xc, 0xff, 0xf4, + 0x7, 0xff, 0xf4, 0x8, 0xee, 0x80, 0x4f, 0xff, + 0x70, 0x0, 0x7f, 0xfe, 0x40, 0x0, 0x4, 0xef, + 0xf8, 0x0, 0x0, 0x4, 0xdf, 0xfc, 0x88, 0xcf, + 0xfd, 0x40, 0x0, 0x0, 0x0, 0x5, 0xad, 0xff, + 0xda, 0x50, 0x0, 0x0, + + /* U+F070 "" */ + 0x8c, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xdf, 0xe4, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x1b, 0xff, 0x80, 0x49, + 0xdf, 0xfd, 0xa5, 0x0, 0x0, 0x0, 0x0, 0x7f, + 0xff, 0xff, 0xd8, 0x8c, 0xff, 0xd4, 0x0, 0x0, + 0x0, 0x4, 0xef, 0xf8, 0x0, 0x0, 0x4e, 0xff, + 0x70, 0x0, 0x0, 0x0, 0x1c, 0xff, 0x69, 0xe8, + 0x4, 0xff, 0xf7, 0x0, 0x4, 0xe3, 0x0, 0x9f, + 0xfe, 0xff, 0x80, 0xcf, 0xff, 0x40, 0xd, 0xff, + 0x70, 0x5, 0xff, 0xff, 0xe0, 0x8f, 0xff, 0xd0, + 0xd, 0xff, 0xf7, 0x0, 0x2d, 0xff, 0xe0, 0x8f, + 0xff, 0xd0, 0x4, 0xff, 0xfc, 0x0, 0x0, 0xaf, + 0xf8, 0xcf, 0xff, 0x30, 0x0, 0x7f, 0xff, 0x40, + 0x0, 0x6, 0xff, 0xff, 0xf7, 0x0, 0x0, 0x8, + 0xff, 0xf4, 0x0, 0x0, 0x3e, 0xff, 0xa0, 0x0, + 0x0, 0x0, 0x4d, 0xff, 0xc8, 0x82, 0x1, 0xbf, + 0xf7, 0x0, 0x0, 0x0, 0x0, 0x5a, 0xdf, 0xfc, + 0x10, 0x8, 0xff, 0xa0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x4e, 0xfd, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xc8, + + /* U+F071 "" */ + 0x0, 0x0, 0x0, 0x0, 0x2d, 0xd2, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xbf, 0xfb, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5, + 0xff, 0xff, 0x50, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xd, 0xff, 0xff, 0xd0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x7f, 0xff, 0xff, 0xf7, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x1, 0xff, 0xd8, 0x8d, + 0xff, 0x10, 0x0, 0x0, 0x0, 0x0, 0xa, 0xff, + 0xa0, 0xa, 0xff, 0xa0, 0x0, 0x0, 0x0, 0x0, + 0x3f, 0xff, 0xb0, 0xb, 0xff, 0xf3, 0x0, 0x0, + 0x0, 0x0, 0xcf, 0xff, 0xc0, 0xc, 0xff, 0xfc, + 0x0, 0x0, 0x0, 0x5, 0xff, 0xff, 0xd0, 0xd, + 0xff, 0xff, 0x50, 0x0, 0x0, 0xe, 0xff, 0xff, + 0xf9, 0x9f, 0xff, 0xff, 0xe0, 0x0, 0x0, 0x8f, + 0xff, 0xff, 0xe2, 0x2e, 0xff, 0xff, 0xf8, 0x0, + 0x2, 0xff, 0xff, 0xff, 0x90, 0x9, 0xff, 0xff, + 0xff, 0x10, 0xa, 0xff, 0xff, 0xff, 0xe3, 0x3e, + 0xff, 0xff, 0xff, 0xa0, 0xf, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x8, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, + + /* U+F074 "" */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xd8, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x80, + 0xff, 0xff, 0x70, 0x0, 0x7, 0xff, 0xff, 0xf8, + 0xff, 0xff, 0xf6, 0x0, 0x6f, 0xff, 0xff, 0xfd, + 0x78, 0x8e, 0xff, 0x15, 0xff, 0xe8, 0xff, 0xe2, + 0x0, 0x2, 0xe5, 0x4f, 0xfe, 0x20, 0xfe, 0x20, + 0x0, 0x0, 0x13, 0xff, 0xf3, 0x0, 0x52, 0x0, + 0x0, 0x0, 0x3f, 0xff, 0x31, 0x0, 0x52, 0x0, + 0x0, 0x2, 0xef, 0xf4, 0x5e, 0x20, 0xfe, 0x20, + 0x78, 0x8e, 0xff, 0x51, 0xff, 0xe8, 0xff, 0xe2, + 0xff, 0xff, 0xf6, 0x0, 0x6f, 0xff, 0xff, 0xfd, + 0xff, 0xff, 0x70, 0x0, 0x7, 0xff, 0xff, 0xf8, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x80, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xd8, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + + /* U+F077 "" */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x1, 0xdd, 0x10, 0x0, 0x0, 0x0, 0x0, + 0x1d, 0xff, 0xd1, 0x0, 0x0, 0x0, 0x1, 0xdf, + 0xff, 0xfd, 0x10, 0x0, 0x0, 0x1d, 0xff, 0x99, + 0xff, 0xd1, 0x0, 0x1, 0xdf, 0xf9, 0x0, 0x9f, + 0xfd, 0x10, 0x1d, 0xff, 0x90, 0x0, 0x9, 0xff, + 0xd1, 0xbf, 0xf9, 0x0, 0x0, 0x0, 0x9f, 0xfb, + 0x5f, 0x90, 0x0, 0x0, 0x0, 0x9, 0xf5, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + + /* U+F078 "" */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5f, + 0x90, 0x0, 0x0, 0x0, 0x9, 0xf5, 0xbf, 0xf9, + 0x0, 0x0, 0x0, 0x9f, 0xfb, 0x1d, 0xff, 0x90, + 0x0, 0x9, 0xff, 0xd1, 0x1, 0xdf, 0xf9, 0x0, + 0x9f, 0xfd, 0x10, 0x0, 0x1d, 0xff, 0x99, 0xff, + 0xd1, 0x0, 0x0, 0x1, 0xdf, 0xff, 0xfd, 0x10, + 0x0, 0x0, 0x0, 0x1d, 0xff, 0xd1, 0x0, 0x0, + 0x0, 0x0, 0x1, 0xdd, 0x10, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + + /* U+F079 "" */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x1d, 0xd1, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x1, 0xdf, 0xfd, 0x10, + 0xef, 0xff, 0xff, 0xff, 0xd0, 0x0, 0x1d, 0xff, + 0xff, 0xd1, 0xaf, 0xff, 0xff, 0xff, 0xf0, 0x0, + 0xcf, 0xcf, 0xfc, 0xfc, 0x0, 0x0, 0x0, 0xf, + 0xf0, 0x0, 0x6b, 0x1f, 0xf1, 0xb6, 0x0, 0x0, + 0x0, 0xf, 0xf0, 0x0, 0x0, 0xf, 0xf0, 0x0, + 0x0, 0x0, 0x0, 0xf, 0xf0, 0x0, 0x0, 0xf, + 0xf0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf0, 0x0, + 0x0, 0xf, 0xf0, 0x0, 0x0, 0x0, 0x6b, 0x1f, + 0xf1, 0xb6, 0x0, 0xf, 0xf0, 0x0, 0x0, 0x0, + 0xcf, 0xcf, 0xfc, 0xfc, 0x0, 0xf, 0xff, 0xff, + 0xff, 0xfa, 0x1d, 0xff, 0xff, 0xd1, 0x0, 0xd, + 0xff, 0xff, 0xff, 0xfe, 0x1, 0xdf, 0xfd, 0x10, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1d, + 0xd1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, + + /* U+F07B "" */ + 0x8f, 0xff, 0xff, 0xe2, 0x0, 0x0, 0x0, 0x0, + 0xff, 0xff, 0xff, 0xfe, 0x20, 0x0, 0x0, 0x0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, + + /* U+F093 "" */ + 0x0, 0x0, 0x0, 0xb, 0xb0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xbf, 0xfb, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xb, 0xff, 0xff, 0xb0, 0x0, 0x0, + 0x0, 0x0, 0xbf, 0xff, 0xff, 0xfb, 0x0, 0x0, + 0x0, 0xb, 0xff, 0xff, 0xff, 0xff, 0xb0, 0x0, + 0x0, 0x4f, 0xff, 0xff, 0xff, 0xff, 0xf4, 0x0, + 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, + 0xdf, 0xff, 0xf0, 0xdf, 0xfd, 0xf, 0xff, 0xfd, + 0xff, 0xff, 0xf9, 0x0, 0x0, 0x9f, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xe0, 0xff, + 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, + + /* U+F095 "" */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0xea, + 0x62, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0xff, + 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9f, + 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, + 0xff, 0xff, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x2, + 0xff, 0xff, 0xfb, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x3, 0xef, 0xff, 0x70, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x4, 0xff, 0xf2, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xbf, 0xfb, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x6f, 0xff, 0x30, 0x0, 0x0, 0x2, + 0x0, 0x0, 0x4f, 0xff, 0x90, 0x0, 0x2, 0x8f, + 0xf3, 0x0, 0x6f, 0xff, 0xd0, 0x0, 0xa, 0xff, + 0xff, 0xe4, 0xbf, 0xff, 0xd1, 0x0, 0x0, 0xef, + 0xff, 0xff, 0xff, 0xff, 0xd1, 0x0, 0x0, 0xa, + 0xff, 0xff, 0xff, 0xff, 0x90, 0x0, 0x0, 0x0, + 0x6f, 0xff, 0xff, 0xfb, 0x30, 0x0, 0x0, 0x0, + 0x2, 0xff, 0xdb, 0x72, 0x0, 0x0, 0x0, 0x0, + 0x0, + + /* U+F0C4 "" */ + 0x8, 0xee, 0x80, 0x0, 0x0, 0x6, 0x61, 0x8, + 0xff, 0xff, 0x80, 0x0, 0x2d, 0xff, 0xd0, 0xef, + 0x33, 0xfe, 0x0, 0x2e, 0xff, 0xf3, 0xe, 0xf3, + 0x3f, 0xe0, 0x2e, 0xff, 0xf3, 0x0, 0x8f, 0xff, + 0xff, 0x6e, 0xff, 0xf3, 0x0, 0x0, 0x8e, 0xff, + 0xff, 0xff, 0xf3, 0x0, 0x0, 0x0, 0x2, 0xef, + 0xff, 0xf3, 0x0, 0x0, 0x0, 0x0, 0x2e, 0xff, + 0xff, 0x30, 0x0, 0x0, 0x8, 0xef, 0xff, 0xff, + 0xff, 0x30, 0x0, 0x8, 0xff, 0xff, 0xf6, 0xef, + 0xff, 0x30, 0x0, 0xef, 0x33, 0xfe, 0x2, 0xef, + 0xff, 0x30, 0xe, 0xf3, 0x3f, 0xe0, 0x2, 0xef, + 0xff, 0x30, 0x8f, 0xff, 0xf8, 0x0, 0x2, 0xdf, + 0xfd, 0x0, 0x8e, 0xe8, 0x0, 0x0, 0x0, 0x66, + 0x10, + + /* U+F0C5 "" */ + 0x0, 0x0, 0xdf, 0xff, 0xff, 0xd, 0x20, 0x0, + 0x0, 0xff, 0xff, 0xff, 0xf, 0xe2, 0x0, 0x0, + 0xff, 0xff, 0xff, 0xf, 0xfd, 0xdf, 0xf0, 0xff, + 0xff, 0xff, 0x20, 0x0, 0xff, 0xf0, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xdf, 0xff, + 0xff, 0xff, 0xfd, 0xff, 0xf9, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, + 0x0, 0xdf, 0xff, 0xff, 0xff, 0xfd, 0x0, 0x0, + + /* U+F0C7 "" */ + 0x8f, 0xff, 0xff, 0xff, 0xff, 0xc2, 0x0, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0x20, 0xff, 0x0, + 0x0, 0x0, 0x1, 0xff, 0xe2, 0xff, 0x0, 0x0, + 0x0, 0x0, 0xff, 0xfc, 0xff, 0x0, 0x0, 0x0, + 0x0, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xfb, 0x11, 0xbf, 0xff, 0xff, 0xff, + 0xff, 0xf1, 0x0, 0x1f, 0xff, 0xff, 0xff, 0xff, + 0xf1, 0x0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xfb, + 0x11, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x8f, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xf8, + + /* U+F0E7 "" */ + 0x0, 0xdf, 0xff, 0xfd, 0x0, 0x0, 0x1, 0xff, + 0xff, 0xfc, 0x0, 0x0, 0x3, 0xff, 0xff, 0xf7, + 0x0, 0x0, 0x6, 0xff, 0xff, 0xf2, 0x0, 0x0, + 0x8, 0xff, 0xff, 0xd0, 0x0, 0x0, 0xa, 0xff, + 0xff, 0xff, 0xff, 0xd0, 0xc, 0xff, 0xff, 0xff, + 0xff, 0xa0, 0xe, 0xff, 0xff, 0xff, 0xff, 0x20, + 0xd, 0xff, 0xff, 0xff, 0xf8, 0x0, 0x0, 0x0, + 0xa, 0xff, 0xe0, 0x0, 0x0, 0x0, 0xe, 0xff, + 0x50, 0x0, 0x0, 0x0, 0x2f, 0xfc, 0x0, 0x0, + 0x0, 0x0, 0x5f, 0xf3, 0x0, 0x0, 0x0, 0x0, + 0x9f, 0xa0, 0x0, 0x0, 0x0, 0x0, 0xdf, 0x10, + 0x0, 0x0, 0x0, 0x0, 0xd7, 0x0, 0x0, 0x0, + + /* U+F0EA "" */ + 0x0, 0x4, 0xee, 0x40, 0x0, 0x0, 0x0, 0xdf, + 0xff, 0x99, 0xff, 0xfd, 0x0, 0x0, 0xff, 0xff, + 0x99, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x90, 0x0, + 0x0, 0x0, 0x0, 0xff, 0xff, 0xd, 0xff, 0xff, + 0xd, 0x20, 0xff, 0xff, 0xf, 0xff, 0xff, 0xf, + 0xe2, 0xff, 0xff, 0xf, 0xff, 0xff, 0xf, 0xfd, + 0xff, 0xff, 0xf, 0xff, 0xff, 0x20, 0x0, 0xff, + 0xff, 0xf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf, + 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xf, 0xff, + 0xff, 0xff, 0xff, 0x0, 0x0, 0xf, 0xff, 0xff, + 0xff, 0xff, 0x0, 0x0, 0xf, 0xff, 0xff, 0xff, + 0xff, 0x0, 0x0, 0xd, 0xff, 0xff, 0xff, 0xfd, + + /* U+F0F3 "" */ + 0x0, 0x0, 0x0, 0xcc, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x2, 0xff, 0x30, 0x0, 0x0, 0x0, 0x1, + 0xbf, 0xff, 0xfc, 0x20, 0x0, 0x0, 0x1e, 0xff, + 0xff, 0xff, 0xe1, 0x0, 0x0, 0x9f, 0xff, 0xff, + 0xff, 0xf8, 0x0, 0x0, 0xef, 0xff, 0xff, 0xff, + 0xfd, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x0, 0x1, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, + 0x3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x30, 0x8, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x1e, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xe1, 0xcf, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xfc, 0xcf, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xe, 0xff, 0xe0, 0x0, + 0x0, 0x0, 0x0, 0x4, 0xee, 0x40, 0x0, 0x0, + + /* U+F11C "" */ + 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x0, 0xf0, 0xf, 0x0, 0xf0, + 0xf, 0x0, 0xff, 0xff, 0x0, 0xf0, 0xf, 0x0, + 0xf0, 0xf, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x8, + 0x80, 0x88, 0x8, 0x80, 0x8f, 0xff, 0xff, 0xf8, + 0x8, 0x80, 0x88, 0x8, 0x80, 0x8f, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x0, 0xf0, 0x0, 0x0, 0x0, 0xf, 0x0, + 0xff, 0xff, 0x0, 0xf0, 0x0, 0x0, 0x0, 0xf, + 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x8f, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xf8, + + /* U+F124 "" */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, + 0xaf, 0x70, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, + 0xcf, 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x6, + 0xdf, 0xff, 0xff, 0xa0, 0x0, 0x0, 0x0, 0x17, + 0xef, 0xff, 0xff, 0xff, 0x30, 0x0, 0x0, 0x18, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0x0, 0x0, 0x2a, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf4, 0x0, 0x8, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd0, 0x0, + 0xf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x60, + 0x0, 0x8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, + 0xf7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, + 0xff, 0xf1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xff, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xff, 0xff, 0x10, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xff, 0xfa, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xff, 0xf2, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x8f, 0x80, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, + + /* U+F15B "" */ + 0xdf, 0xff, 0xff, 0xf0, 0xd2, 0x0, 0xff, 0xff, + 0xff, 0xf0, 0xfe, 0x20, 0xff, 0xff, 0xff, 0xf0, + 0xff, 0xe2, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xfd, + 0xff, 0xff, 0xff, 0xf2, 0x0, 0x0, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xfd, + + /* U+F1EB "" */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x4, 0x9c, 0xef, 0xfe, + 0xc9, 0x40, 0x0, 0x0, 0x0, 0x7, 0xef, 0xff, + 0xff, 0xff, 0xff, 0xfe, 0x70, 0x0, 0x4, 0xdf, + 0xff, 0xfc, 0xa8, 0x8a, 0xcf, 0xff, 0xfd, 0x40, + 0x6f, 0xff, 0xd5, 0x0, 0x0, 0x0, 0x0, 0x5d, + 0xff, 0xf6, 0xcf, 0xf6, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x6f, 0xfc, 0x1a, 0x30, 0x0, 0x5a, + 0xdf, 0xfd, 0xa5, 0x0, 0x3, 0xa1, 0x0, 0x0, + 0x4d, 0xff, 0xff, 0xff, 0xff, 0xd4, 0x0, 0x0, + 0x0, 0x5, 0xff, 0xfe, 0xa8, 0x8a, 0xef, 0xff, + 0x50, 0x0, 0x0, 0x1, 0xdf, 0x70, 0x0, 0x0, + 0x7, 0xfd, 0x10, 0x0, 0x0, 0x0, 0x12, 0x0, + 0x0, 0x0, 0x0, 0x21, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x4e, 0xe4, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xef, 0xfe, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xef, 0xfe, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x4e, 0xe4, 0x0, 0x0, 0x0, 0x0, + + /* U+F240 "" */ + 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xf0, 0xff, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, 0xff, 0xf, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf, 0xff, + 0xff, 0xf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x0, 0xff, 0xff, 0xf, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x0, 0xff, 0xff, 0xf, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xf, 0xff, 0xff, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xf0, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x80, + + /* U+F241 "" */ + 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xf0, 0xff, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, 0xff, 0xf, + 0xff, 0xff, 0xff, 0xff, 0xf0, 0x0, 0xf, 0xff, + 0xff, 0xf, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x0, + 0x0, 0xff, 0xff, 0xf, 0xff, 0xff, 0xff, 0xff, + 0xf0, 0x0, 0x0, 0xff, 0xff, 0xf, 0xff, 0xff, + 0xff, 0xff, 0xf0, 0x0, 0xf, 0xff, 0xff, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xf0, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x80, + + /* U+F242 "" */ + 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xf0, 0xff, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, 0xff, 0xf, + 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0xf, 0xff, + 0xff, 0xf, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, + 0x0, 0xff, 0xff, 0xf, 0xff, 0xff, 0xff, 0x0, + 0x0, 0x0, 0x0, 0xff, 0xff, 0xf, 0xff, 0xff, + 0xff, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xf0, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x80, + + /* U+F243 "" */ + 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xf0, 0xff, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, 0xff, 0xf, + 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, + 0xff, 0xf, 0xff, 0xf0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xff, 0xff, 0xf, 0xff, 0xf0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xff, 0xff, 0xf, 0xff, 0xf0, + 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xf0, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x80, + + /* U+F244 "" */ + 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xf0, 0xff, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, 0xff, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, + 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xfd, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xf0, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x80, + + /* U+F287 "" */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, + 0xfd, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x1, 0xcf, 0xff, 0xf5, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0xb9, 0x29, 0xfe, 0x10, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0x10, 0x2, + 0x0, 0x0, 0x0, 0x0, 0x3, 0xdf, 0x80, 0xa, + 0x90, 0x0, 0x0, 0x0, 0x3, 0x70, 0x0, 0xdf, + 0xff, 0x77, 0xf7, 0x55, 0x55, 0x55, 0x55, 0x8f, + 0xd3, 0xf, 0xff, 0xfd, 0xcc, 0xdf, 0xdc, 0xcc, + 0xcc, 0xcd, 0xff, 0xb0, 0x8f, 0xfe, 0x10, 0x0, + 0xaa, 0x0, 0x0, 0x0, 0x4d, 0x40, 0x0, 0x46, + 0x10, 0x0, 0x1, 0xf2, 0x2, 0x33, 0x10, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x9, 0xb1, 0xcf, + 0xf9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xa, 0xff, 0xff, 0x90, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xbf, 0xf9, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x22, + 0x0, 0x0, 0x0, + + /* U+F293 "" */ + 0x0, 0x18, 0xdf, 0xfd, 0x92, 0x0, 0x2, 0xef, + 0xfb, 0xef, 0xff, 0x30, 0xd, 0xff, 0xfa, 0x2e, + 0xff, 0xe0, 0x4f, 0xff, 0xfa, 0x3, 0xff, 0xf5, + 0x9f, 0xfa, 0xfa, 0x35, 0x4f, 0xfa, 0xcf, 0xc0, + 0x8a, 0x3d, 0xb, 0xfd, 0xef, 0xfb, 0x3, 0x12, + 0x8f, 0xfe, 0xff, 0xff, 0xb0, 0x6, 0xff, 0xff, + 0xff, 0xff, 0xd1, 0x8, 0xff, 0xff, 0xef, 0xfd, + 0x11, 0x10, 0x9f, 0xff, 0xdf, 0xd1, 0x59, 0x3b, + 0xb, 0xfd, 0xaf, 0xd7, 0xfa, 0x38, 0x1d, 0xfb, + 0x5f, 0xff, 0xfa, 0x1, 0xdf, 0xf7, 0xd, 0xff, + 0xfa, 0x1d, 0xff, 0xf1, 0x3, 0xef, 0xfc, 0xdf, + 0xff, 0x50, 0x0, 0x18, 0xdf, 0xfe, 0xa3, 0x0, + + /* U+F2ED "" */ + 0x0, 0x0, 0x7f, 0xff, 0xf7, 0x0, 0x0, 0xef, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xef, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xf0, 0xf, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xf0, 0xf, 0xf9, 0x9f, 0x99, 0xf9, 0x9f, + 0xf0, 0xf, 0xf8, 0x8f, 0x88, 0xf8, 0x8f, 0xf0, + 0xf, 0xf8, 0x8f, 0x88, 0xf8, 0x8f, 0xf0, 0xf, + 0xf8, 0x8f, 0x88, 0xf8, 0x8f, 0xf0, 0xf, 0xf8, + 0x8f, 0x88, 0xf8, 0x8f, 0xf0, 0xf, 0xf8, 0x8f, + 0x88, 0xf8, 0x8f, 0xf0, 0xf, 0xf8, 0x8f, 0x88, + 0xf8, 0x8f, 0xf0, 0xf, 0xf9, 0x9f, 0x99, 0xf9, + 0x9f, 0xf0, 0xf, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf0, 0x8, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, + + /* U+F304 "" */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f, 0xa0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8f, 0xff, + 0xb0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xd, 0xff, + 0xff, 0xa0, 0x0, 0x0, 0x0, 0x0, 0x8a, 0x1d, + 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x8f, 0xfa, + 0x1d, 0xff, 0x70, 0x0, 0x0, 0x0, 0x8f, 0xff, + 0xfa, 0x1d, 0x80, 0x0, 0x0, 0x0, 0x8f, 0xff, + 0xff, 0xfa, 0x0, 0x0, 0x0, 0x0, 0x8f, 0xff, + 0xff, 0xff, 0x80, 0x0, 0x0, 0x0, 0x8f, 0xff, + 0xff, 0xff, 0x80, 0x0, 0x0, 0x0, 0x8f, 0xff, + 0xff, 0xff, 0x80, 0x0, 0x0, 0x0, 0x8f, 0xff, + 0xff, 0xff, 0x80, 0x0, 0x0, 0x0, 0x6f, 0xff, + 0xff, 0xff, 0x80, 0x0, 0x0, 0x0, 0xb, 0xff, + 0xff, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, 0xdf, + 0xff, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, 0xe, + 0xff, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xde, 0xdb, 0x60, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, + + /* U+F55A "" */ + 0x0, 0x0, 0x1b, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xe4, 0x0, 0x1, 0xdf, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xfe, 0x0, 0x1d, 0xff, 0xff, + 0xfa, 0xef, 0xfe, 0xaf, 0xff, 0xff, 0x1, 0xdf, + 0xff, 0xff, 0xa0, 0x2e, 0xe2, 0xa, 0xff, 0xff, + 0x1d, 0xff, 0xff, 0xff, 0xe2, 0x2, 0x20, 0x2e, + 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xfe, 0x20, + 0x2, 0xef, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, + 0xfe, 0x20, 0x2, 0xef, 0xff, 0xff, 0x1d, 0xff, + 0xff, 0xff, 0xe2, 0x2, 0x20, 0x2e, 0xff, 0xff, + 0x1, 0xdf, 0xff, 0xff, 0xa0, 0x2e, 0xe2, 0xa, + 0xff, 0xff, 0x0, 0x1d, 0xff, 0xff, 0xfa, 0xef, + 0xfe, 0xaf, 0xff, 0xff, 0x0, 0x1, 0xdf, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0, 0x0, + 0x1b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe4, + + /* U+F7C2 "" */ + 0x0, 0x8, 0xff, 0xff, 0xff, 0xe4, 0x0, 0x8f, + 0xff, 0xff, 0xff, 0xfe, 0x8, 0xf8, 0xf, 0xb, + 0x40, 0xff, 0x8f, 0xf8, 0xf, 0xb, 0x40, 0xff, + 0xff, 0xf8, 0xf, 0xb, 0x40, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, + 0xff, 0xfe, 0x4e, 0xff, 0xff, 0xff, 0xff, 0xe4, + + /* U+F8A2 "" */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, + 0xe0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x2, + 0xef, 0x10, 0x0, 0xbf, 0x0, 0x0, 0x0, 0x0, + 0x7f, 0xf1, 0x0, 0xcf, 0xf1, 0x0, 0x0, 0x0, + 0x7, 0xff, 0x11, 0xcf, 0xff, 0x77, 0x77, 0x77, + 0x77, 0xbf, 0xf1, 0xcf, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x17, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xe0, 0x7, 0xff, 0xf1, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0xff, 0x10, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5, 0xa0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 +}; + + +/*--------------------- + * GLYPH DESCRIPTION + *--------------------*/ + +static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = { + {.bitmap_index = 0, .adv_w = 0, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0} /* id = 0 reserved */, + {.bitmap_index = 0, .adv_w = 69, .box_w = 0, .box_h = 0, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 0, .adv_w = 69, .box_w = 3, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 18, .adv_w = 100, .box_w = 5, .box_h = 5, .ofs_x = 1, .ofs_y = 7}, + {.bitmap_index = 31, .adv_w = 180, .box_w = 11, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 97, .adv_w = 159, .box_w = 10, .box_h = 16, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 177, .adv_w = 216, .box_w = 13, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 255, .adv_w = 176, .box_w = 11, .box_h = 13, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 327, .adv_w = 54, .box_w = 2, .box_h = 5, .ofs_x = 1, .ofs_y = 7}, + {.bitmap_index = 332, .adv_w = 86, .box_w = 4, .box_h = 15, .ofs_x = 1, .ofs_y = -3}, + {.bitmap_index = 362, .adv_w = 87, .box_w = 4, .box_h = 15, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 392, .adv_w = 102, .box_w = 7, .box_h = 7, .ofs_x = 0, .ofs_y = 5}, + {.bitmap_index = 417, .adv_w = 149, .box_w = 8, .box_h = 8, .ofs_x = 1, .ofs_y = 2}, + {.bitmap_index = 449, .adv_w = 98, .box_w = 6, .box_h = 3, .ofs_x = 0, .ofs_y = 3}, + {.bitmap_index = 458, .adv_w = 58, .box_w = 3, .box_h = 3, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 463, .adv_w = 90, .box_w = 8, .box_h = 16, .ofs_x = -1, .ofs_y = -2}, + {.bitmap_index = 527, .adv_w = 171, .box_w = 10, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 587, .adv_w = 95, .box_w = 5, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 617, .adv_w = 147, .box_w = 9, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 671, .adv_w = 146, .box_w = 9, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 725, .adv_w = 171, .box_w = 11, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 791, .adv_w = 147, .box_w = 9, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 845, .adv_w = 158, .box_w = 10, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 905, .adv_w = 153, .box_w = 9, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 959, .adv_w = 165, .box_w = 10, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1019, .adv_w = 158, .box_w = 10, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1079, .adv_w = 58, .box_w = 3, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1093, .adv_w = 58, .box_w = 3, .box_h = 12, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 1111, .adv_w = 149, .box_w = 8, .box_h = 8, .ofs_x = 1, .ofs_y = 2}, + {.bitmap_index = 1143, .adv_w = 149, .box_w = 8, .box_h = 6, .ofs_x = 1, .ofs_y = 3}, + {.bitmap_index = 1167, .adv_w = 149, .box_w = 8, .box_h = 8, .ofs_x = 1, .ofs_y = 2}, + {.bitmap_index = 1199, .adv_w = 147, .box_w = 9, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1253, .adv_w = 265, .box_w = 16, .box_h = 15, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 1373, .adv_w = 187, .box_w = 13, .box_h = 12, .ofs_x = -1, .ofs_y = 0}, + {.bitmap_index = 1451, .adv_w = 194, .box_w = 11, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1517, .adv_w = 185, .box_w = 11, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1583, .adv_w = 211, .box_w = 12, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1655, .adv_w = 172, .box_w = 9, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1709, .adv_w = 163, .box_w = 9, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1763, .adv_w = 198, .box_w = 12, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 1835, .adv_w = 208, .box_w = 11, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1901, .adv_w = 79, .box_w = 3, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 1919, .adv_w = 131, .box_w = 8, .box_h = 12, .ofs_x = -1, .ofs_y = 0}, + {.bitmap_index = 1967, .adv_w = 184, .box_w = 11, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2033, .adv_w = 152, .box_w = 9, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2087, .adv_w = 244, .box_w = 13, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2165, .adv_w = 208, .box_w = 11, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2231, .adv_w = 215, .box_w = 13, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 2309, .adv_w = 185, .box_w = 10, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2369, .adv_w = 215, .box_w = 14, .box_h = 15, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 2474, .adv_w = 186, .box_w = 10, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2534, .adv_w = 159, .box_w = 10, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 2594, .adv_w = 150, .box_w = 10, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 2654, .adv_w = 202, .box_w = 11, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 2720, .adv_w = 182, .box_w = 13, .box_h = 12, .ofs_x = -1, .ofs_y = 0}, + {.bitmap_index = 2798, .adv_w = 288, .box_w = 18, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 2906, .adv_w = 172, .box_w = 11, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 2972, .adv_w = 166, .box_w = 12, .box_h = 12, .ofs_x = -1, .ofs_y = 0}, + {.bitmap_index = 3044, .adv_w = 168, .box_w = 11, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 3110, .adv_w = 85, .box_w = 5, .box_h = 15, .ofs_x = 1, .ofs_y = -3}, + {.bitmap_index = 3148, .adv_w = 90, .box_w = 8, .box_h = 16, .ofs_x = -1, .ofs_y = -2}, + {.bitmap_index = 3212, .adv_w = 85, .box_w = 4, .box_h = 15, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 3242, .adv_w = 149, .box_w = 8, .box_h = 7, .ofs_x = 1, .ofs_y = 2}, + {.bitmap_index = 3270, .adv_w = 128, .box_w = 8, .box_h = 2, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 3278, .adv_w = 154, .box_w = 5, .box_h = 2, .ofs_x = 1, .ofs_y = 10}, + {.bitmap_index = 3283, .adv_w = 153, .box_w = 9, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 3324, .adv_w = 175, .box_w = 10, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 3384, .adv_w = 146, .box_w = 9, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 3425, .adv_w = 175, .box_w = 10, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 3485, .adv_w = 157, .box_w = 10, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 3530, .adv_w = 90, .box_w = 7, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 3572, .adv_w = 177, .box_w = 10, .box_h = 12, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 3632, .adv_w = 174, .box_w = 9, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 3686, .adv_w = 71, .box_w = 3, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 3704, .adv_w = 73, .box_w = 6, .box_h = 15, .ofs_x = -2, .ofs_y = -3}, + {.bitmap_index = 3749, .adv_w = 158, .box_w = 9, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 3803, .adv_w = 71, .box_w = 2, .box_h = 12, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 3815, .adv_w = 271, .box_w = 15, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 3883, .adv_w = 174, .box_w = 9, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 3924, .adv_w = 163, .box_w = 10, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 3969, .adv_w = 175, .box_w = 10, .box_h = 12, .ofs_x = 1, .ofs_y = -3}, + {.bitmap_index = 4029, .adv_w = 175, .box_w = 10, .box_h = 12, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 4089, .adv_w = 105, .box_w = 6, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 4116, .adv_w = 128, .box_w = 8, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 4152, .adv_w = 106, .box_w = 7, .box_h = 11, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 4191, .adv_w = 173, .box_w = 9, .box_h = 9, .ofs_x = 1, .ofs_y = 0}, + {.bitmap_index = 4232, .adv_w = 143, .box_w = 10, .box_h = 9, .ofs_x = -1, .ofs_y = 0}, + {.bitmap_index = 4277, .adv_w = 230, .box_w = 15, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 4345, .adv_w = 141, .box_w = 9, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 4386, .adv_w = 143, .box_w = 10, .box_h = 12, .ofs_x = -1, .ofs_y = -3}, + {.bitmap_index = 4446, .adv_w = 133, .box_w = 8, .box_h = 9, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 4482, .adv_w = 90, .box_w = 6, .box_h = 15, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 4527, .adv_w = 77, .box_w = 3, .box_h = 15, .ofs_x = 1, .ofs_y = -3}, + {.bitmap_index = 4550, .adv_w = 90, .box_w = 5, .box_h = 15, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 4588, .adv_w = 149, .box_w = 9, .box_h = 5, .ofs_x = 0, .ofs_y = 4}, + {.bitmap_index = 4611, .adv_w = 256, .box_w = 16, .box_h = 17, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 4747, .adv_w = 256, .box_w = 16, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 4843, .adv_w = 256, .box_w = 16, .box_h = 14, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 4955, .adv_w = 256, .box_w = 16, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 5051, .adv_w = 176, .box_w = 11, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 5117, .adv_w = 256, .box_w = 16, .box_h = 16, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 5245, .adv_w = 256, .box_w = 16, .box_h = 16, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 5373, .adv_w = 288, .box_w = 18, .box_h = 14, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 5499, .adv_w = 256, .box_w = 16, .box_h = 16, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 5627, .adv_w = 288, .box_w = 18, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 5735, .adv_w = 256, .box_w = 16, .box_h = 16, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 5863, .adv_w = 128, .box_w = 8, .box_h = 14, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 5919, .adv_w = 192, .box_w = 12, .box_h = 14, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 6003, .adv_w = 288, .box_w = 18, .box_h = 16, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 6147, .adv_w = 256, .box_w = 16, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 6243, .adv_w = 224, .box_w = 10, .box_h = 16, .ofs_x = 2, .ofs_y = -2}, + {.bitmap_index = 6323, .adv_w = 224, .box_w = 14, .box_h = 18, .ofs_x = 0, .ofs_y = -3}, + {.bitmap_index = 6449, .adv_w = 224, .box_w = 14, .box_h = 15, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 6554, .adv_w = 224, .box_w = 14, .box_h = 14, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 6652, .adv_w = 224, .box_w = 10, .box_h = 16, .ofs_x = 2, .ofs_y = -2}, + {.bitmap_index = 6732, .adv_w = 224, .box_w = 16, .box_h = 14, .ofs_x = -1, .ofs_y = -1}, + {.bitmap_index = 6844, .adv_w = 160, .box_w = 10, .box_h = 14, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 6914, .adv_w = 160, .box_w = 10, .box_h = 14, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 6984, .adv_w = 224, .box_w = 14, .box_h = 14, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 7082, .adv_w = 224, .box_w = 14, .box_h = 4, .ofs_x = 0, .ofs_y = 4}, + {.bitmap_index = 7110, .adv_w = 288, .box_w = 18, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 7218, .adv_w = 320, .box_w = 20, .box_h = 16, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 7378, .adv_w = 288, .box_w = 20, .box_h = 16, .ofs_x = -1, .ofs_y = -2}, + {.bitmap_index = 7538, .adv_w = 256, .box_w = 16, .box_h = 16, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 7666, .adv_w = 224, .box_w = 14, .box_h = 10, .ofs_x = 0, .ofs_y = 1}, + {.bitmap_index = 7736, .adv_w = 224, .box_w = 14, .box_h = 10, .ofs_x = 0, .ofs_y = 1}, + {.bitmap_index = 7806, .adv_w = 320, .box_w = 20, .box_h = 14, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 7946, .adv_w = 256, .box_w = 16, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 8042, .adv_w = 256, .box_w = 16, .box_h = 16, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 8170, .adv_w = 256, .box_w = 17, .box_h = 17, .ofs_x = -1, .ofs_y = -2}, + {.bitmap_index = 8315, .adv_w = 224, .box_w = 15, .box_h = 14, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 8420, .adv_w = 224, .box_w = 14, .box_h = 16, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 8532, .adv_w = 224, .box_w = 14, .box_h = 14, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 8630, .adv_w = 160, .box_w = 12, .box_h = 16, .ofs_x = -1, .ofs_y = -2}, + {.bitmap_index = 8726, .adv_w = 224, .box_w = 14, .box_h = 16, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 8838, .adv_w = 224, .box_w = 14, .box_h = 16, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 8950, .adv_w = 288, .box_w = 18, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 9058, .adv_w = 256, .box_w = 18, .box_h = 18, .ofs_x = -1, .ofs_y = -3}, + {.bitmap_index = 9220, .adv_w = 192, .box_w = 12, .box_h = 16, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 9316, .adv_w = 320, .box_w = 20, .box_h = 15, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 9466, .adv_w = 320, .box_w = 20, .box_h = 10, .ofs_x = 0, .ofs_y = 1}, + {.bitmap_index = 9566, .adv_w = 320, .box_w = 20, .box_h = 10, .ofs_x = 0, .ofs_y = 1}, + {.bitmap_index = 9666, .adv_w = 320, .box_w = 20, .box_h = 10, .ofs_x = 0, .ofs_y = 1}, + {.bitmap_index = 9766, .adv_w = 320, .box_w = 20, .box_h = 10, .ofs_x = 0, .ofs_y = 1}, + {.bitmap_index = 9866, .adv_w = 320, .box_w = 20, .box_h = 10, .ofs_x = 0, .ofs_y = 1}, + {.bitmap_index = 9966, .adv_w = 320, .box_w = 21, .box_h = 14, .ofs_x = 0, .ofs_y = -1}, + {.bitmap_index = 10113, .adv_w = 224, .box_w = 12, .box_h = 16, .ofs_x = 1, .ofs_y = -2}, + {.bitmap_index = 10209, .adv_w = 224, .box_w = 14, .box_h = 16, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 10321, .adv_w = 256, .box_w = 17, .box_h = 17, .ofs_x = -1, .ofs_y = -3}, + {.bitmap_index = 10466, .adv_w = 320, .box_w = 20, .box_h = 12, .ofs_x = 0, .ofs_y = 0}, + {.bitmap_index = 10586, .adv_w = 192, .box_w = 12, .box_h = 16, .ofs_x = 0, .ofs_y = -2}, + {.bitmap_index = 10682, .adv_w = 258, .box_w = 17, .box_h = 11, .ofs_x = 0, .ofs_y = 1} +}; + +/*--------------------- + * CHARACTER MAPPING + *--------------------*/ + +static const uint16_t unicode_list_2[] = { + 0x0, 0x7, 0xa, 0xb, 0xc, 0x10, 0x12, 0x14, + 0x18, 0x1b, 0x20, 0x25, 0x26, 0x27, 0x3d, 0x47, + 0x4a, 0x4b, 0x4c, 0x50, 0x51, 0x52, 0x53, 0x66, + 0x67, 0x6d, 0x6f, 0x70, 0x73, 0x76, 0x77, 0x78, + 0x7a, 0x92, 0x94, 0xc3, 0xc4, 0xc6, 0xe6, 0xe9, + 0xf2, 0x11b, 0x123, 0x15a, 0x1ea, 0x23f, 0x240, 0x241, + 0x242, 0x243, 0x286, 0x292, 0x2ec, 0x303, 0x559, 0x7c1, + 0x8a1 +}; + +/*Collect the unicode lists and glyph_id offsets*/ +static const lv_font_fmt_txt_cmap_t cmaps[] = +{ + { + .range_start = 32, .range_length = 12, .glyph_id_start = 1, + .unicode_list = NULL, .glyph_id_ofs_list = NULL, .list_length = 0, .type = LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY + }, + { + .range_start = 45, .range_length = 82, .glyph_id_start = 13, + .unicode_list = NULL, .glyph_id_ofs_list = NULL, .list_length = 0, .type = LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY + }, + { + .range_start = 61441, .range_length = 2210, .glyph_id_start = 95, + .unicode_list = unicode_list_2, .glyph_id_ofs_list = NULL, .list_length = 57, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY + } +}; + +/*----------------- + * KERNING + *----------------*/ + + +/*Map glyph_ids to kern left classes*/ +static const uint8_t kern_left_class_mapping[] = +{ + 0, 0, 1, 2, 0, 3, 4, 5, + 2, 6, 7, 8, 9, 9, 10, 11, + 12, 0, 13, 14, 15, 16, 17, 18, + 19, 12, 20, 20, 0, 0, 0, 21, + 22, 23, 24, 25, 22, 26, 27, 28, + 29, 29, 30, 31, 32, 29, 29, 22, + 33, 34, 35, 3, 36, 30, 37, 37, + 38, 39, 40, 41, 42, 43, 0, 44, + 0, 45, 46, 47, 48, 49, 50, 51, + 45, 52, 52, 53, 48, 45, 45, 46, + 46, 54, 55, 56, 57, 51, 58, 58, + 59, 58, 60, 41, 0, 0, 9, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/*Map glyph_ids to kern right classes*/ +static const uint8_t kern_right_class_mapping[] = +{ + 0, 0, 1, 2, 0, 3, 4, 5, + 2, 6, 7, 8, 9, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 12, 18, + 19, 20, 21, 21, 0, 0, 0, 22, + 23, 24, 25, 23, 25, 25, 25, 23, + 25, 25, 26, 25, 25, 25, 25, 23, + 25, 23, 25, 3, 27, 28, 29, 29, + 30, 31, 32, 33, 34, 35, 0, 36, + 0, 37, 38, 39, 39, 39, 0, 39, + 38, 40, 41, 38, 38, 42, 42, 39, + 42, 39, 42, 43, 44, 45, 46, 46, + 47, 46, 48, 0, 0, 35, 9, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/*Kern values between classes*/ +static const int8_t kern_class_values[] = +{ + 0, 1, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 3, 0, 0, 0, + 0, 2, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 12, 0, 7, -6, 0, 0, 0, + 0, -14, -15, 2, 12, 6, 4, -10, + 2, 13, 1, 11, 3, 8, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 15, 2, -2, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, -8, 0, 0, 0, 0, 0, -5, + 4, 5, 0, 0, -3, 0, -2, 3, + 0, -3, 0, -3, -1, -5, 0, 0, + 0, 0, -3, 0, 0, -3, -4, 0, + 0, -3, 0, -5, 0, 0, 0, 0, + 0, 0, 0, 0, 0, -3, -3, 0, + 0, -7, 0, -31, 0, 0, -5, 0, + 5, 8, 0, 0, -5, 3, 3, 8, + 5, -4, 5, 0, 0, -15, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, -9, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + -3, -13, 0, -10, -2, 0, 0, 0, + 0, 1, 10, 0, -8, -2, -1, 1, + 0, -4, 0, 0, -2, -19, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, -20, -2, 10, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 8, 0, 3, 0, 0, -5, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 10, 2, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -9, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 2, 5, 3, 8, -3, 0, 0, 5, + -3, -8, -35, 2, 7, 5, 1, -3, + 0, 9, 0, 8, 0, 8, 0, -24, + 0, -3, 8, 0, 8, -3, 5, 3, + 0, 0, 1, -3, 0, 0, -4, 20, + 0, 20, 0, 8, 0, 11, 3, 4, + 0, 0, 0, -9, 0, 0, 0, 0, + 1, -2, 0, 2, -5, -3, -5, 2, + 0, -3, 0, 0, 0, -10, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, -17, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, -14, 0, -16, 0, 0, 0, 0, + -2, 0, 25, -3, -3, 3, 3, -2, + 0, -3, 3, 0, 0, -14, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, -25, 0, 3, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 15, 0, 0, -9, 0, 8, 0, + -17, -25, -17, -5, 8, 0, 0, -17, + 0, 3, -6, 0, -4, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 7, 8, -31, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2, 0, 0, 0, 0, 0, 2, + 2, -3, -5, 0, -1, -1, -3, 0, + 0, -2, 0, 0, 0, -5, 0, -2, + 0, -6, -5, 0, -6, -8, -8, -5, + 0, -5, 0, -5, 0, 0, 0, 0, + -2, 0, 0, 3, 0, 2, -3, 0, + 0, 0, 0, 3, -2, 0, 0, 0, + -2, 3, 3, -1, 0, 0, 0, -5, + 0, -1, 0, 0, 0, 0, 0, 1, + 0, 3, -2, 0, -3, 0, -4, 0, + 0, -2, 0, 8, 0, 0, -3, 0, + 0, 0, 0, 0, -1, 1, -2, -2, + 0, -3, 0, -3, 0, 0, 0, 0, + 0, 0, 0, 0, 0, -1, -1, 0, + -3, -3, 0, 0, 0, 0, 0, 1, + 0, 0, -2, 0, -3, -3, -3, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + -2, 0, 0, 0, 0, -2, -3, 0, + 0, -8, -2, -8, 5, 0, 0, -5, + 3, 5, 7, 0, -6, -1, -3, 0, + -1, -12, 3, -2, 2, -14, 3, 0, + 0, 1, -13, 0, -14, -2, -22, -2, + 0, -13, 0, 5, 7, 0, 3, 0, + 0, 0, 0, 1, 0, -5, -3, 0, + 0, 0, 0, -3, 0, 0, 0, -3, + 0, 0, 0, 0, 0, -1, -1, 0, + -1, -3, 0, 0, 0, 0, 0, 0, + 0, -3, -3, 0, -2, -3, -2, 0, + 0, -3, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, -2, -2, 0, + 0, -2, 0, -5, 3, 0, 0, -3, + 1, 3, 3, 0, 0, 0, 0, 0, + 0, -2, 0, 0, 0, 0, 0, 2, + 0, 0, -3, 0, -3, -2, -3, 0, + 0, 0, 0, 0, 0, 0, 2, 0, + -2, 0, 0, 0, 0, -3, -4, 0, + 0, 8, -2, 1, -8, 0, 0, 7, + -13, -13, -11, -5, 3, 0, -2, -17, + -5, 0, -5, 0, -5, 4, -5, -16, + 0, -7, 0, 0, 1, -1, 2, -2, + 0, 3, 0, -8, -10, 0, -13, -6, + -5, -6, -8, -3, -7, -1, -5, -7, + 0, 1, 0, -3, 0, 0, 0, 2, + 0, 3, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, -3, 0, -1, + 0, -1, -3, 0, -4, -6, -6, -1, + 0, -8, 0, 0, 0, 0, 0, 0, + -2, 0, 0, 0, 0, 1, -2, 0, + 0, 3, 0, 0, 0, 0, 0, 0, + 0, 0, 12, 0, 0, 0, 0, 0, + 0, 2, 0, 0, 0, -3, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, -5, 0, 3, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + -2, 0, 0, 0, -5, 0, 0, 0, + 0, -13, -8, 0, 0, 0, -4, -13, + 0, 0, -3, 3, 0, -7, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + -4, 0, 0, -5, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, -5, 0, 0, 0, 0, 3, 0, + 2, -5, -5, 0, -3, -3, -3, 0, + 0, 0, 0, 0, 0, -8, 0, -3, + 0, -4, -3, 0, -6, -6, -8, -2, + 0, -5, 0, -8, 0, 0, 0, 0, + 20, 0, 0, 1, 0, 0, -3, 0, + 0, -11, 0, 0, 0, 0, 0, -24, + -5, 8, 8, -2, -11, 0, 3, -4, + 0, -13, -1, -3, 3, -18, -3, 3, + 0, 4, -9, -4, -9, -8, -11, 0, + 0, -15, 0, 15, 0, 0, -1, 0, + 0, 0, -1, -1, -3, -7, -8, -1, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -3, 0, -1, -3, -4, 0, + 0, -5, 0, -3, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -1, 0, -5, 0, 0, 5, + -1, 3, 0, -6, 3, -2, -1, -7, + -3, 0, -3, -3, -2, 0, -4, -4, + 0, 0, -2, -1, -2, -4, -3, 0, + 0, -3, 0, 3, -2, 0, -6, 0, + 0, 0, -5, 0, -4, 0, -4, -4, + 0, 0, 0, 0, 0, 0, 0, 0, + -5, 3, 0, -4, 0, -2, -3, -8, + -2, -2, -2, -1, -2, -3, -1, 0, + 0, 0, 0, 0, -3, -2, -2, 0, + 0, 0, 0, 3, -2, 0, -2, 0, + 0, 0, -2, -3, -2, -2, -3, -2, + 2, 10, -1, 0, -7, 0, -2, 5, + 0, -3, -11, -3, 4, 0, 0, -12, + -4, 3, -4, 2, 0, -2, -2, -8, + 0, -4, 1, 0, 0, -4, 0, 0, + 0, 3, 3, -5, -5, 0, -4, -3, + -4, -3, -3, 0, -4, 1, -5, -4, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 3, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, -4, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, -2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, -2, -3, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, -4, + 0, 0, -3, 0, 0, -3, -3, 0, + 0, 0, 0, -3, 0, 0, 0, 0, + -1, 0, 0, 0, 0, 0, -2, 0, + 0, 0, -4, 0, -5, 0, 0, 0, + -8, 0, 2, -6, 5, 1, -2, -12, + 0, 0, -6, -3, 0, -10, -6, -7, + 0, 0, -11, -3, -10, -10, -12, 0, + -7, 0, 2, 17, -3, 0, -6, -3, + -1, -3, -4, -7, -5, -9, -10, -6, + 0, 0, -2, 0, 1, 0, 0, -18, + -2, 8, 6, -6, -9, 0, 1, -8, + 0, -13, -2, -3, 5, -24, -3, 1, + 0, 0, -17, -3, -13, -3, -19, 0, + 0, -18, 0, 15, 1, 0, -2, 0, + 0, 0, 0, -1, -2, -10, -2, 0, + 0, 0, 0, 0, -8, 0, -2, 0, + -1, -7, -12, 0, 0, -1, -4, -8, + -3, 0, -2, 0, 0, 0, 0, -12, + -3, -8, -8, -2, -4, -6, -3, -4, + 0, -5, -2, -8, -4, 0, -3, -5, + -3, -5, 0, 1, 0, -2, -8, 0, + 0, -5, 0, 0, 0, 0, 3, 0, + 2, -5, 10, 0, -3, -3, -3, 0, + 0, 0, 0, 0, 0, -8, 0, -3, + 0, -4, -3, 0, -6, -6, -8, -2, + 0, -5, 2, 10, 0, 0, 0, 0, + 20, 0, 0, 1, 0, 0, -3, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + -1, 0, 0, 0, 0, 0, -2, -5, + 0, 0, 0, 0, 0, -1, 0, 0, + 0, -3, -3, 0, 0, -5, -3, 0, + 0, -5, 0, 4, -1, 0, 0, 0, + 0, 0, 0, 1, 0, 0, 0, 0, + 5, 2, -2, 0, -8, -4, 0, 8, + -8, -8, -5, -5, 10, 5, 3, -22, + -2, 5, -3, 0, -3, 3, -3, -9, + 0, -3, 3, -3, -2, -8, -2, 0, + 0, 8, 5, 0, -7, 0, -14, -3, + 7, -3, -10, 1, -3, -8, -8, -3, + 3, 0, -4, 0, -7, 0, 2, 8, + -6, -9, -10, -6, 8, 0, 1, -19, + -2, 3, -4, -2, -6, 0, -6, -9, + -4, -4, -2, 0, 0, -6, -5, -3, + 0, 8, 6, -3, -14, 0, -14, -4, + 0, -9, -15, -1, -8, -4, -8, -7, + 0, 0, -3, 0, -5, -2, 0, -3, + -5, 0, 4, -8, 3, 0, 0, -14, + 0, -3, -6, -4, -2, -8, -6, -8, + -6, 0, -8, -3, -6, -5, -8, -3, + 0, 0, 1, 12, -4, 0, -8, -3, + 0, -3, -5, -6, -7, -7, -10, -3, + 5, 0, -4, 0, -13, -3, 2, 5, + -8, -9, -5, -8, 8, -3, 1, -24, + -5, 5, -6, -4, -9, 0, -8, -11, + -3, -3, -2, -3, -5, -8, -1, 0, + 0, 8, 7, -2, -17, 0, -15, -6, + 6, -10, -17, -5, -9, -11, -13, -8, + 0, 0, 0, 0, -3, 0, 0, 3, + -3, 5, 2, -5, 5, 0, 0, -8, + -1, 0, -1, 0, 1, 1, -2, 0, + 0, 0, 0, 0, 0, -3, 0, 0, + 0, 0, 2, 8, 1, 0, -3, 0, + 0, 0, 0, -2, -2, -3, 0, 0, + 1, 2, 0, 0, 0, 0, 2, 0, + -2, 0, 10, 0, 5, 1, 1, -3, + 0, 5, 0, 0, 0, 2, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 8, 0, 7, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, -15, 0, -3, 4, 0, 8, 0, + 0, 25, 3, -5, -5, 3, 3, -2, + 1, -13, 0, 0, 12, -15, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, -17, 10, 36, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -4, 0, 0, -5, -2, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, -2, 0, -7, 0, 0, 1, 0, + 0, 3, 33, -5, -2, 8, 7, -7, + 3, 0, 0, 3, 3, -3, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, -33, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, -7, 0, 0, 0, -7, + 0, 0, 0, 0, -6, -1, 0, 0, + 0, -6, 0, -3, 0, -12, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, -17, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, -3, 0, 0, + 0, -4, 0, -7, 0, 0, 0, -4, + 3, -3, 0, 0, -7, -3, -6, 0, + 0, -7, 0, -3, 0, -12, 0, -3, + 0, 0, -21, -5, -10, -3, -9, 0, + 0, -17, 0, -7, -1, 0, 0, 0, + 0, 0, 0, 0, 0, -4, -5, -2, + 0, 0, 0, 0, -6, 0, -6, 3, + -3, 5, 0, -2, -6, -2, -4, -5, + 0, -3, -1, -2, 2, -7, -1, 0, + 0, 0, -23, -2, -4, 0, -6, 0, + -2, -12, -2, 0, 0, -2, -2, 0, + 0, 0, 0, 2, 0, -2, -4, -2, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 3, 0, 0, 0, 0, + 0, -6, 0, -2, 0, 0, 0, -5, + 3, 0, 0, 0, -7, -3, -5, 0, + 0, -7, 0, -3, 0, -12, 0, 0, + 0, 0, -25, 0, -5, -9, -13, 0, + 0, -17, 0, -2, -4, 0, 0, 0, + 0, 0, 0, 0, 0, -3, -4, -1, + 1, 0, 0, 4, -3, 0, 8, 13, + -3, -3, -8, 3, 13, 4, 6, -7, + 3, 11, 3, 7, 6, 7, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 16, 12, -5, -3, 0, -2, 20, + 11, 20, 0, 0, 0, 3, 0, 0, + 0, 0, -4, 0, 0, 0, 0, 0, + 0, 0, 0, 0, -2, 0, 0, 0, + 0, 0, 0, 0, 0, 4, 0, 0, + 0, 0, -22, -3, -2, -10, -13, 0, + 0, -17, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -4, 0, 0, 0, 0, 0, + 0, 0, 0, 0, -2, 0, 0, 0, + 0, 0, 0, 0, 0, 4, 0, 0, + 0, 0, -22, -3, -2, -10, -13, 0, + 0, -10, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, -2, 0, 0, 0, + -6, 3, 0, -3, 2, 5, 3, -8, + 0, -1, -2, 3, 0, 2, 0, 0, + 0, 0, -6, 0, -2, -2, -5, 0, + -2, -10, 0, 16, -3, 0, -6, -2, + 0, -2, -4, 0, -3, -7, -5, -3, + 0, 0, -4, 0, 0, 0, 0, 0, + 0, 0, 0, 0, -2, 0, 0, 0, + 0, 0, 0, 0, 0, 4, 0, 0, + 0, 0, -22, -3, -2, -10, -13, 0, + 0, -17, 0, 0, 0, 0, 0, 0, + 13, 0, 0, 0, 0, 0, 0, 0, + 0, 0, -4, 0, -8, -3, -2, 8, + -2, -3, -10, 1, -2, 1, -2, -7, + 1, 6, 1, 2, 1, 2, -6, -10, + -3, 0, -10, -5, -7, -11, -10, 0, + -4, -5, -3, -3, -2, -2, -3, -2, + 0, -2, -1, 4, 0, 4, -2, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, -2, -3, -3, 0, + 0, -7, 0, -1, 0, -4, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, -15, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, -3, -3, 0, + 0, 0, 0, 0, -2, 0, 0, -4, + -3, 3, 0, -4, -5, -2, 0, -7, + -2, -6, -2, -3, 0, -4, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, -17, 0, 8, 0, 0, -5, 0, + 0, 0, 0, -3, 0, -3, 0, 0, + 0, 0, -2, 0, -6, 0, 0, 11, + -3, -8, -8, 2, 3, 3, -1, -7, + 2, 4, 2, 8, 2, 8, -2, -7, + 0, 0, -10, 0, 0, -8, -7, 0, + 0, -5, 0, -3, -4, 0, -4, 0, + -4, 0, -2, 4, 0, -2, -8, -3, + 0, 0, -2, 0, -5, 0, 0, 3, + -6, 0, 3, -3, 2, 0, 0, -8, + 0, -2, -1, 0, -3, 3, -2, 0, + 0, 0, -10, -3, -6, 0, -8, 0, + 0, -12, 0, 9, -3, 0, -5, 0, + 2, 0, -3, 0, -3, -8, 0, -3, + 0, 0, 0, 0, -2, 0, 0, 3, + -3, 1, 0, 0, -3, -2, 0, -3, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, -16, 0, 6, 0, 0, -2, 0, + 0, 0, 0, 1, 0, -3, -3, 0 +}; + + +/*Collect the kern class' data in one place*/ +static const lv_font_fmt_txt_kern_classes_t kern_classes = +{ + .class_pair_values = kern_class_values, + .left_class_mapping = kern_left_class_mapping, + .right_class_mapping = kern_right_class_mapping, + .left_class_cnt = 60, + .right_class_cnt = 48, +}; + +/*-------------------- + * ALL CUSTOM DATA + *--------------------*/ + +#if LV_VERSION_CHECK(8, 0, 0) +/*Store all the custom data of the font*/ +static lv_font_fmt_txt_glyph_cache_t cache; +static const lv_font_fmt_txt_dsc_t font_dsc = { +#else +static lv_font_fmt_txt_dsc_t font_dsc = { +#endif + .glyph_bitmap = glyph_bitmap, + .glyph_dsc = glyph_dsc, + .cmaps = cmaps, + .kern_dsc = &kern_classes, + .kern_scale = 16, + .cmap_num = 3, + .bpp = 4, + .kern_classes = 1, + .bitmap_format = 0, +#if LV_VERSION_CHECK(8, 0, 0) + .cache = &cache +#endif +}; + + +/*----------------- + * PUBLIC FONT + *----------------*/ + +/*Initialize a public general font descriptor*/ +#if LV_VERSION_CHECK(8, 0, 0) +const lv_font_t lv_font_montserratMedium_16 = { +#else +lv_font_t lv_font_montserratMedium_16 = { +#endif + .get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt, /*Function pointer to get glyph's data*/ + .get_glyph_bitmap = lv_font_get_bitmap_fmt_txt, /*Function pointer to get glyph's bitmap*/ + .line_height = 16, /*The maximum line height required by the font default: (f.src.ascent - f.src.descent)*/ + .base_line = 2.4, /*Baseline measured from the bottom of the line*/ +#if !(LVGL_VERSION_MAJOR == 6 && LVGL_VERSION_MINOR == 0) + .subpx = LV_FONT_SUBPX_NONE, +#endif +#if LV_VERSION_CHECK(7, 4, 0) || LVGL_VERSION_MAJOR >= 8 + .underline_position = -1, + .underline_thickness = 1, +#endif + .dsc = &font_dsc /*The custom font data. Will be accessed by `get_glyph_bitmap/dsc` */ +}; + + + +#endif /*#if LV_FONT_MONTSERRATMEDIUM_16*/ + diff --git a/code/08.gui/lvgl_spd2010_gui/main/ui/generated/images/images.mk b/code/08.gui/lvgl_spd2010_gui/main/ui/generated/images/images.mk new file mode 100644 index 0000000..60a7a4d --- /dev/null +++ b/code/08.gui/lvgl_spd2010_gui/main/ui/generated/images/images.mk @@ -0,0 +1,6 @@ +GEN_CSRCS += $(notdir $(wildcard $(PRJ_DIR)/generated/images/*.c)) + +DEPPATH += --dep-path $(PRJ_DIR)/generated/images +VPATH += :$(PRJ_DIR)/generated/images + +CFLAGS += "-I$(PRJ_DIR)/generated/images" \ No newline at end of file diff --git a/code/08.gui/lvgl_spd2010_gui/main/ui/generated/setup_scr_screen.c b/code/08.gui/lvgl_spd2010_gui/main/ui/generated/setup_scr_screen.c new file mode 100644 index 0000000..4f4ffd7 --- /dev/null +++ b/code/08.gui/lvgl_spd2010_gui/main/ui/generated/setup_scr_screen.c @@ -0,0 +1,90 @@ +/* +* Copyright 2024 NXP +* NXP Confidential and Proprietary. This software is owned or controlled by NXP and may only be used strictly in +* accordance with the applicable license terms. By expressly accepting such terms or by downloading, installing, +* activating and/or otherwise using the software, you are agreeing that you have read, and that you agree to +* comply with and are bound by, such license terms. If you do not agree to be bound by the applicable license +* terms, then you may not retain, install, activate or otherwise use the software. +*/ + +#include "lvgl.h" +#include +#include "gui_guider.h" +#include "events_init.h" +#include "widgets_init.h" +#include "custom.h" + + +void setup_scr_screen(lv_ui *ui) +{ + //Write codes screen + ui->screen = lv_obj_create(NULL); + lv_obj_set_size(ui->screen, 412, 412); + + //Write style for screen, Part: LV_PART_MAIN, State: LV_STATE_DEFAULT. + lv_obj_set_style_bg_opa(ui->screen, 0, LV_PART_MAIN|LV_STATE_DEFAULT); + + //Write codes screen_btn_1 + ui->screen_btn_1 = lv_btn_create(ui->screen); + ui->screen_btn_1_label = lv_label_create(ui->screen_btn_1); + lv_label_set_text(ui->screen_btn_1_label, "Button"); + lv_label_set_long_mode(ui->screen_btn_1_label, LV_LABEL_LONG_WRAP); + lv_obj_align(ui->screen_btn_1_label, LV_ALIGN_CENTER, 0, 0); + lv_obj_set_style_pad_all(ui->screen_btn_1, 0, LV_STATE_DEFAULT); + lv_obj_set_pos(ui->screen_btn_1, 156, 290); + lv_obj_set_size(ui->screen_btn_1, 100, 50); + + //Write style for screen_btn_1, Part: LV_PART_MAIN, State: LV_STATE_DEFAULT. + lv_obj_set_style_bg_opa(ui->screen_btn_1, 255, LV_PART_MAIN|LV_STATE_DEFAULT); + lv_obj_set_style_bg_color(ui->screen_btn_1, lv_color_hex(0x2195f6), LV_PART_MAIN|LV_STATE_DEFAULT); + lv_obj_set_style_border_width(ui->screen_btn_1, 0, LV_PART_MAIN|LV_STATE_DEFAULT); + lv_obj_set_style_radius(ui->screen_btn_1, 5, LV_PART_MAIN|LV_STATE_DEFAULT); + lv_obj_set_style_shadow_width(ui->screen_btn_1, 0, LV_PART_MAIN|LV_STATE_DEFAULT); + lv_obj_set_style_text_color(ui->screen_btn_1, lv_color_hex(0xffffff), LV_PART_MAIN|LV_STATE_DEFAULT); + lv_obj_set_style_text_font(ui->screen_btn_1, &lv_font_montserratMedium_16, LV_PART_MAIN|LV_STATE_DEFAULT); + lv_obj_set_style_text_align(ui->screen_btn_1, LV_TEXT_ALIGN_CENTER, LV_PART_MAIN|LV_STATE_DEFAULT); + + //Write codes screen_chart_1 + ui->screen_chart_1 = lv_chart_create(ui->screen); + lv_chart_set_type(ui->screen_chart_1, LV_CHART_TYPE_LINE); + lv_chart_set_div_line_count(ui->screen_chart_1, 3, 5); + lv_chart_set_point_count(ui->screen_chart_1, 5); + lv_chart_set_range(ui->screen_chart_1, LV_CHART_AXIS_PRIMARY_Y, 0, 100); + lv_chart_set_range(ui->screen_chart_1, LV_CHART_AXIS_SECONDARY_Y, 0, 100); + lv_chart_set_zoom_x(ui->screen_chart_1, 256); + lv_chart_set_zoom_y(ui->screen_chart_1, 256); + lv_chart_series_t * screen_chart_1_0 = lv_chart_add_series(ui->screen_chart_1, lv_color_hex(0x000000), LV_CHART_AXIS_PRIMARY_Y); + lv_chart_set_next_value(ui->screen_chart_1, screen_chart_1_0, 1); + lv_chart_set_next_value(ui->screen_chart_1, screen_chart_1_0, 20); + lv_chart_set_next_value(ui->screen_chart_1, screen_chart_1_0, 30); + lv_chart_set_next_value(ui->screen_chart_1, screen_chart_1_0, 40); + lv_chart_set_next_value(ui->screen_chart_1, screen_chart_1_0, 5); + lv_obj_set_pos(ui->screen_chart_1, 104, 100); + lv_obj_set_size(ui->screen_chart_1, 205, 155); + lv_obj_set_scrollbar_mode(ui->screen_chart_1, LV_SCROLLBAR_MODE_OFF); + + //Write style for screen_chart_1, Part: LV_PART_MAIN, State: LV_STATE_DEFAULT. + lv_obj_set_style_bg_opa(ui->screen_chart_1, 255, LV_PART_MAIN|LV_STATE_DEFAULT); + lv_obj_set_style_bg_color(ui->screen_chart_1, lv_color_hex(0xffffff), LV_PART_MAIN|LV_STATE_DEFAULT); + lv_obj_set_style_border_width(ui->screen_chart_1, 1, LV_PART_MAIN|LV_STATE_DEFAULT); + lv_obj_set_style_border_opa(ui->screen_chart_1, 255, LV_PART_MAIN|LV_STATE_DEFAULT); + lv_obj_set_style_border_color(ui->screen_chart_1, lv_color_hex(0xe8e8e8), LV_PART_MAIN|LV_STATE_DEFAULT); + lv_obj_set_style_border_side(ui->screen_chart_1, LV_BORDER_SIDE_FULL, LV_PART_MAIN|LV_STATE_DEFAULT); + lv_obj_set_style_radius(ui->screen_chart_1, 0, LV_PART_MAIN|LV_STATE_DEFAULT); + lv_obj_set_style_line_width(ui->screen_chart_1, 2, LV_PART_MAIN|LV_STATE_DEFAULT); + lv_obj_set_style_line_color(ui->screen_chart_1, lv_color_hex(0xe8e8e8), LV_PART_MAIN|LV_STATE_DEFAULT); + lv_obj_set_style_line_opa(ui->screen_chart_1, 255, LV_PART_MAIN|LV_STATE_DEFAULT); + lv_obj_set_style_shadow_width(ui->screen_chart_1, 0, LV_PART_MAIN|LV_STATE_DEFAULT); + + //Write style for screen_chart_1, Part: LV_PART_TICKS, State: LV_STATE_DEFAULT. + lv_obj_set_style_text_color(ui->screen_chart_1, lv_color_hex(0x151212), LV_PART_TICKS|LV_STATE_DEFAULT); + lv_obj_set_style_text_font(ui->screen_chart_1, &lv_font_montserratMedium_12, LV_PART_TICKS|LV_STATE_DEFAULT); + lv_obj_set_style_line_width(ui->screen_chart_1, 2, LV_PART_TICKS|LV_STATE_DEFAULT); + lv_obj_set_style_line_color(ui->screen_chart_1, lv_color_hex(0xe8e8e8), LV_PART_TICKS|LV_STATE_DEFAULT); + lv_obj_set_style_line_opa(ui->screen_chart_1, 255, LV_PART_TICKS|LV_STATE_DEFAULT); + + //Update current screen layout. + lv_obj_update_layout(ui->screen); + + +} diff --git a/code/08.gui/lvgl_spd2010_gui/main/ui/generated/widgets_init.c b/code/08.gui/lvgl_spd2010_gui/main/ui/generated/widgets_init.c new file mode 100644 index 0000000..958ae3d --- /dev/null +++ b/code/08.gui/lvgl_spd2010_gui/main/ui/generated/widgets_init.c @@ -0,0 +1,78 @@ +/* +* Copyright 2024 NXP +* NXP Confidential and Proprietary. This software is owned or controlled by NXP and may only be used strictly in +* accordance with the applicable license terms. By expressly accepting such terms or by downloading, installing, +* activating and/or otherwise using the software, you are agreeing that you have read, and that you agree to +* comply with and are bound by, such license terms. If you do not agree to be bound by the applicable license +* terms, then you may not retain, install, activate or otherwise use the software. +*/ + +#include "lvgl.h" +#include "gui_guider.h" +#include "widgets_init.h" +#include + + +__attribute__((unused)) void kb_event_cb (lv_event_t *e) { + lv_event_code_t code = lv_event_get_code(e); + lv_obj_t *kb = lv_event_get_target(e); + if(code == LV_EVENT_READY || code == LV_EVENT_CANCEL){ + lv_obj_add_flag(kb, LV_OBJ_FLAG_HIDDEN); + } +} + +__attribute__((unused)) void ta_event_cb (lv_event_t *e) { + lv_event_code_t code = lv_event_get_code(e); +#if LV_USE_KEYBOARD || LV_USE_ZH_KEYBOARD + lv_obj_t *ta = lv_event_get_target(e); +#endif + lv_obj_t *kb = lv_event_get_user_data(e); + if (code == LV_EVENT_FOCUSED || code == LV_EVENT_CLICKED) + { +#if LV_USE_ZH_KEYBOARD != 0 + lv_zh_keyboard_set_textarea(kb, ta); +#endif +#if LV_USE_KEYBOARD != 0 + lv_keyboard_set_textarea(kb, ta); +#endif + lv_obj_move_foreground(kb); + lv_obj_clear_flag(kb, LV_OBJ_FLAG_HIDDEN); + } + if (code == LV_EVENT_CANCEL || code == LV_EVENT_DEFOCUSED) + { + +#if LV_USE_ZH_KEYBOARD != 0 + lv_zh_keyboard_set_textarea(kb, ta); +#endif +#if LV_USE_KEYBOARD != 0 + lv_keyboard_set_textarea(kb, ta); +#endif + lv_obj_move_background(kb); + lv_obj_add_flag(kb, LV_OBJ_FLAG_HIDDEN); + } +} + +#if LV_USE_ANALOGCLOCK != 0 +void clock_count(int *hour, int *min, int *sec) +{ + (*sec)++; + if(*sec == 60) + { + *sec = 0; + (*min)++; + } + if(*min == 60) + { + *min = 0; + if(*hour < 12) + { + (*hour)++; + } else { + (*hour)++; + *hour = *hour %12; + } + } +} +#endif + + diff --git a/code/08.gui/lvgl_spd2010_gui/main/ui/generated/widgets_init.h b/code/08.gui/lvgl_spd2010_gui/main/ui/generated/widgets_init.h new file mode 100644 index 0000000..55fa3c5 --- /dev/null +++ b/code/08.gui/lvgl_spd2010_gui/main/ui/generated/widgets_init.h @@ -0,0 +1,30 @@ +/* +* Copyright 2024 NXP +* NXP Confidential and Proprietary. This software is owned or controlled by NXP and may only be used strictly in +* accordance with the applicable license terms. By expressly accepting such terms or by downloading, installing, +* activating and/or otherwise using the software, you are agreeing that you have read, and that you agree to +* comply with and are bound by, such license terms. If you do not agree to be bound by the applicable license +* terms, then you may not retain, install, activate or otherwise use the software. +*/ + +#ifndef WIDGET_INIT_H +#define WIDGET_INIT_H +#ifdef __cplusplus +extern "C" { +#endif + +#include "lvgl.h" +#include "gui_guider.h" + +__attribute__((unused)) void kb_event_cb(lv_event_t *e); +__attribute__((unused)) void ta_event_cb(lv_event_t *e); +#if LV_USE_ANALOGCLOCK != 0 +void clock_count(int *hour, int *min, int *sec); +#endif + + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/code/08.gui/lvgl_spd2010_gui/partitions.csv b/code/08.gui/lvgl_spd2010_gui/partitions.csv new file mode 100644 index 0000000..57bcbf0 --- /dev/null +++ b/code/08.gui/lvgl_spd2010_gui/partitions.csv @@ -0,0 +1,5 @@ +# Name, Type, SubType, Offset, Size, Flags +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap +nvs, data, nvs, 0x10000, 0x6000, +phy_init, data, phy, , 0x1000, +factory, app, factory, , 0x2c0000, diff --git a/code/08.gui/lvgl_transplant_gc9a01/.gitignore b/code/08.gui/lvgl_transplant_gc9a01/.gitignore new file mode 100644 index 0000000..8da877b --- /dev/null +++ b/code/08.gui/lvgl_transplant_gc9a01/.gitignore @@ -0,0 +1,6 @@ +build +*managed_components +dependencies.lock +sdkconfig +sdkconfig.old + diff --git a/code/08.gui/lvgl_transplant_gc9a01/CMakeLists.txt b/code/08.gui/lvgl_transplant_gc9a01/CMakeLists.txt new file mode 100644 index 0000000..7969748 --- /dev/null +++ b/code/08.gui/lvgl_transplant_gc9a01/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(lvgl_component) diff --git a/code/08.gui/lvgl_transplant_gc9a01/docs/1.28寸ESP32圆形TFT屏幕开发板说明书 V1.01.pdf b/code/08.gui/lvgl_transplant_gc9a01/docs/1.28寸ESP32圆形TFT屏幕开发板说明书 V1.01.pdf new file mode 100644 index 0000000..9450a2e Binary files /dev/null and b/code/08.gui/lvgl_transplant_gc9a01/docs/1.28寸ESP32圆形TFT屏幕开发板说明书 V1.01.pdf differ diff --git a/code/08.gui/lvgl_transplant_gc9a01/docs/原理图.pdf b/code/08.gui/lvgl_transplant_gc9a01/docs/原理图.pdf new file mode 100644 index 0000000..59d1e85 Binary files /dev/null and b/code/08.gui/lvgl_transplant_gc9a01/docs/原理图.pdf differ diff --git a/code/08.gui/lvgl_transplant_gc9a01/main/CMakeLists.txt b/code/08.gui/lvgl_transplant_gc9a01/main/CMakeLists.txt new file mode 100644 index 0000000..cf2c455 --- /dev/null +++ b/code/08.gui/lvgl_transplant_gc9a01/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") diff --git a/code/08.gui/lvgl_transplant_gc9a01/main/idf_component.yml b/code/08.gui/lvgl_transplant_gc9a01/main/idf_component.yml new file mode 100644 index 0000000..259d2a0 --- /dev/null +++ b/code/08.gui/lvgl_transplant_gc9a01/main/idf_component.yml @@ -0,0 +1,18 @@ +## IDF Component Manager Manifest File +dependencies: + lvgl/lvgl: "^8.3.11" + espressif/esp_lcd_gc9a01: "^2.0.0" + ## Required IDF version + idf: + version: ">=4.1.0" + # # Put list of dependencies here + # # For components maintained by Espressif: + # component: "~1.0.0" + # # For 3rd party components: + # username/component: ">=1.0.0,<2.0.0" + # username2/component2: + # version: "~1.0.0" + # # For transient dependencies `public` flag can be set. + # # `public` flag doesn't have an effect dependencies of the `main` component. + # # All dependencies of `main` are public by default. + # public: true diff --git a/code/08.gui/lvgl_transplant_gc9a01/main/main.c b/code/08.gui/lvgl_transplant_gc9a01/main/main.c new file mode 100644 index 0000000..79dae97 --- /dev/null +++ b/code/08.gui/lvgl_transplant_gc9a01/main/main.c @@ -0,0 +1,245 @@ +#include +#include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" +#include "freertos/task.h" +#include "esp_timer.h" +#include "esp_lcd_panel_io.h" +#include "esp_lcd_panel_vendor.h" +#include "esp_lcd_panel_ops.h" +#include "driver/gpio.h" +#include "driver/spi_master.h" +#include "driver/i2c.h" +#include "esp_err.h" +#include "esp_log.h" +#include "lvgl.h" +#include "sdkconfig.h" +#include "esp_lcd_gc9a01.h" // 屏幕驱动 +#include "lv_demos.h" +// Using SPI2 +#define LCD_HOST SPI2_HOST + +// 屏幕尺寸 +#define EXAMPLE_LCD_H_RES 240 +#define EXAMPLE_LCD_V_RES 240 + +// 引脚接线 +// | Name | Description | GPIO | +// | BLK | 背光,悬空使能接地关闭,默认上拉至3.3V | 32 | +// | CS | 片选,低电平使能 | 5 | +// | DC | 数据/命令选择,低电平命令,高电平数据 | 27 | +// | RES | 复位,低电平使能 | 33 | +// | SDA | SPI数据输入端口 | 15 | +// | SCL | SPI时钟信号输入端口 | 14 | +#define EXAMPLE_LCD_BK_LIGHT_ON_LEVEL 1 +#define EXAMPLE_LCD_BK_LIGHT_OFF_LEVEL !EXAMPLE_LCD_BK_LIGHT_ON_LEVEL +#define EXAMPLE_PIN_NUM_BK_LIGHT 32 +#define EXAMPLE_PIN_NUM_LCD_CS 5 +#define EXAMPLE_PIN_NUM_LCD_DC 27 +#define EXAMPLE_PIN_NUM_LCD_RST 33 +#define EXAMPLE_PIN_NUM_DATA0 15 +#define EXAMPLE_PIN_NUM_SCLK 14 + +// 日志标签 +static const char *TAG = "main"; + +static SemaphoreHandle_t lvgl_mux = NULL; + +// LVGL定时器周期 +#define EXAMPLE_LVGL_TICK_PERIOD_MS 2 +// LVGL任务参数 +#define EXAMPLE_LVGL_TASK_MAX_DELAY_MS 500 +#define EXAMPLE_LVGL_TASK_MIN_DELAY_MS 1 +#define EXAMPLE_LVGL_TASK_STACK_SIZE (5 * 1024) +#define EXAMPLE_LVGL_TASK_PRIORITY 2 + + +// 回调函数:颜色传输完成 (通知LVGL刷新) +static bool notify_lvgl_flush_ready(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx) +{ + lv_disp_drv_t *disp_driver = (lv_disp_drv_t *)user_ctx; + lv_disp_flush_ready(disp_driver); + return false; +} + +// 回调函数:刷新屏幕 +static void lvgl_flush_cb(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map) +{ + esp_lcd_panel_handle_t panel_handle = (esp_lcd_panel_handle_t) drv->user_data; + int offsetx1 = area->x1; + int offsetx2 = area->x2; + int offsety1 = area->y1; + int offsety2 = area->y2; + /* Copy a buffer's content to a specific area of the display */ + esp_lcd_panel_draw_bitmap(panel_handle, offsetx1, offsety1, offsetx2 + 1, offsety2 + 1, color_map); +} + +// 回调函数:增加LVGL的tick +static void example_increase_lvgl_tick(void *arg) +{ + /* Tell LVGL how many milliseconds has elapsed */ + lv_tick_inc(EXAMPLE_LVGL_TICK_PERIOD_MS); + +} + + + +static bool example_lvgl_lock(int timeout_ms) +{ + assert(lvgl_mux && "bsp_display_start must be called first"); + + const TickType_t timeout_ticks = (timeout_ms == -1) ? portMAX_DELAY : pdMS_TO_TICKS(timeout_ms); + return xSemaphoreTake(lvgl_mux, timeout_ticks) == pdTRUE; +} + +static void example_lvgl_unlock(void) +{ + assert(lvgl_mux && "bsp_display_start must be called first"); + xSemaphoreGive(lvgl_mux); +} + + + +// 测试UI +void test_ui(void) { + // ESP_LOGI(TAG, "Create a test_ui"); + // // 创建一个屏幕对象 + // lv_obj_t *scr = lv_disp_get_scr_act(NULL); + + // // 创建一个矩形对象 + // lv_obj_t *rect = lv_obj_create(scr); + // lv_obj_set_size(rect, LV_HOR_RES, LV_VER_RES); // 设置矩形大小为屏幕大小 + // lv_obj_set_style_local_bg_color(rect, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLUE); // 设置矩形对象背景颜色为蓝色 + // lv_obj_set_style_outline_color(rect, LV_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_SIZE); // 设置矩形对象背景颜色为白色 + + + + + + +} + +// LVGL任务 +static void example_lvgl_port_task(void *arg) +{ + ESP_LOGI(TAG, "Starting LVGL task"); + ESP_LOGI(TAG, "Display LVGL UI"); + + //test_ui(); + lv_demo_widgets(); + //lv_demo_music(); + + uint32_t task_delay_ms = EXAMPLE_LVGL_TASK_MAX_DELAY_MS; + while (1) { + ESP_LOGI(TAG, "LVGL task"); + /* Lock the mutex due to the LVGL APIs are not thread-safe */ + if (example_lvgl_lock(-1)) { + task_delay_ms = lv_timer_handler(); + /* Release the mutex */ + example_lvgl_unlock(); + } + if (task_delay_ms > EXAMPLE_LVGL_TASK_MAX_DELAY_MS) { + task_delay_ms = EXAMPLE_LVGL_TASK_MAX_DELAY_MS; + } else if (task_delay_ms < EXAMPLE_LVGL_TASK_MIN_DELAY_MS) { + task_delay_ms = EXAMPLE_LVGL_TASK_MIN_DELAY_MS; + } + vTaskDelay(pdMS_TO_TICKS(task_delay_ms)); + } +} + + + +void app_main(void) +{ + static lv_disp_draw_buf_t disp_buf; // contains internal graphic buffer(s) called draw buffer(s) + static lv_disp_drv_t disp_drv; // contains callback functions + + // 配置屏幕背光 + ESP_LOGI(TAG, "Turn off LCD backlight"); + gpio_config_t bk_gpio_config = { + .mode = GPIO_MODE_OUTPUT, + .pin_bit_mask = 1ULL << EXAMPLE_PIN_NUM_BK_LIGHT}; + ESP_ERROR_CHECK(gpio_config(&bk_gpio_config)); + + // 初始化SPI总线 + ESP_LOGI(TAG, "Initialize SPI bus"); + const spi_bus_config_t buscfg = GC9A01_PANEL_BUS_SPI_CONFIG(EXAMPLE_PIN_NUM_SCLK, EXAMPLE_PIN_NUM_DATA0, EXAMPLE_LCD_H_RES * EXAMPLE_LCD_V_RES); + ESP_ERROR_CHECK(spi_bus_initialize(LCD_HOST, &buscfg, SPI_DMA_CH_AUTO)); + + // 创建屏幕句柄 + ESP_LOGI(TAG, "Install panel IO"); + esp_lcd_panel_io_handle_t io_handle = NULL; + const esp_lcd_panel_io_spi_config_t io_config = GC9A01_PANEL_IO_SPI_CONFIG(EXAMPLE_PIN_NUM_LCD_CS, EXAMPLE_PIN_NUM_LCD_DC, notify_lvgl_flush_ready, &disp_drv); + + // 将LCD连接到SPI总线 + ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)LCD_HOST, &io_config, &io_handle)); + + // 创建屏幕驱动句柄 + ESP_LOGI(TAG, "Install GC9A01 panel driver"); + esp_lcd_panel_handle_t panel_handle = NULL; + // 屏幕配置 + const esp_lcd_panel_dev_config_t panel_config = { + .reset_gpio_num = EXAMPLE_PIN_NUM_LCD_RST, // Set to -1 if not use + .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_BGR, + .bits_per_pixel = 16, // Implemented by LCD command `3Ah` (16/18) + //.vendor_config = &vendor_config, + }; + // 创建屏幕实例 + ESP_ERROR_CHECK(esp_lcd_new_panel_gc9a01(io_handle, &panel_config, &panel_handle)); + // 屏幕复位 + ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle)); + // 初始化屏幕 + ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle)); + // 反转颜色 + ESP_ERROR_CHECK(esp_lcd_panel_invert_color(panel_handle, true)); + // 镜像 + ESP_ERROR_CHECK(esp_lcd_panel_mirror(panel_handle, true, false)); + // 打开屏幕 + ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true)); + // 打开背光 + ESP_ERROR_CHECK(gpio_set_level(EXAMPLE_PIN_NUM_BK_LIGHT, EXAMPLE_LCD_BK_LIGHT_ON_LEVEL)); + + + + // 初始化LVGL + ESP_LOGI(TAG, "Initialize LVGL"); + lv_init(); + // 申请内存 两个buf + lv_color_t *buf1 = heap_caps_malloc(EXAMPLE_LCD_H_RES * 50 * sizeof(lv_color_t), MALLOC_CAP_DMA); + assert(buf1); // 检查内存是否申请成功 + lv_color_t *buf2 = heap_caps_malloc(EXAMPLE_LCD_H_RES * 50 * sizeof(lv_color_t), MALLOC_CAP_DMA); + assert(buf2); + // 初始化LVGL显示缓冲区 + lv_disp_draw_buf_init(&disp_buf, buf1, buf2, EXAMPLE_LCD_H_RES * 50); + + // 初始化LVGL显示驱动 + ESP_LOGI(TAG, "Initialize LVGL display driver"); + lv_disp_drv_init(&disp_drv); + disp_drv.hor_res = EXAMPLE_LCD_H_RES; // 设置屏幕水平分辨率 + disp_drv.ver_res = EXAMPLE_LCD_V_RES; // 设置屏幕垂直分辨率 + disp_drv.flush_cb = lvgl_flush_cb; // 设置刷新回调函数 + disp_drv.draw_buf = &disp_buf; // 设置显示缓冲区 + disp_drv.user_data = panel_handle; // 设置用户数据 + lv_disp_t *disp = lv_disp_drv_register(&disp_drv); // 注册显示驱动 + + // 配置输入设备 + ESP_LOGI(TAG, "Initialize LVGL input device"); + // lv_indev_drv_t indev_drv; + + + // 创建定时器 + ESP_LOGI(TAG, "Install LVGL tick timer"); + /* Tick interface for LVGL (using esp_timer to generate 2ms periodic event) */ + const esp_timer_create_args_t lvgl_tick_timer_args = { + .callback = &example_increase_lvgl_tick, + .name = "lvgl_tick" + }; + esp_timer_handle_t lvgl_tick_timer = NULL; + ESP_ERROR_CHECK(esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer)); + ESP_ERROR_CHECK(esp_timer_start_periodic(lvgl_tick_timer, EXAMPLE_LVGL_TICK_PERIOD_MS * 1000)); + + // 创建LVGL任务 + ESP_LOGI(TAG, "Create LVGL task"); + lvgl_mux = xSemaphoreCreateMutex(); + assert(lvgl_mux); + xTaskCreate(example_lvgl_port_task, "LVGL", EXAMPLE_LVGL_TASK_STACK_SIZE, NULL, EXAMPLE_LVGL_TASK_PRIORITY, NULL); +} diff --git a/code/08.gui/lvgl_transplant_gc9a01/partitions.csv b/code/08.gui/lvgl_transplant_gc9a01/partitions.csv new file mode 100644 index 0000000..57bcbf0 --- /dev/null +++ b/code/08.gui/lvgl_transplant_gc9a01/partitions.csv @@ -0,0 +1,5 @@ +# Name, Type, SubType, Offset, Size, Flags +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap +nvs, data, nvs, 0x10000, 0x6000, +phy_init, data, phy, , 0x1000, +factory, app, factory, , 0x2c0000, diff --git a/code/08.gui/lvgl_transplant_spd2010/.gitignore b/code/08.gui/lvgl_transplant_spd2010/.gitignore new file mode 100644 index 0000000..8da877b --- /dev/null +++ b/code/08.gui/lvgl_transplant_spd2010/.gitignore @@ -0,0 +1,6 @@ +build +*managed_components +dependencies.lock +sdkconfig +sdkconfig.old + diff --git a/code/08.gui/lvgl_transplant_spd2010/CMakeLists.txt b/code/08.gui/lvgl_transplant_spd2010/CMakeLists.txt new file mode 100644 index 0000000..bdafdcf --- /dev/null +++ b/code/08.gui/lvgl_transplant_spd2010/CMakeLists.txt @@ -0,0 +1,8 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(lvgl_transplant_spd2010) diff --git a/code/08.gui/lvgl_transplant_spd2010/main/CMakeLists.txt b/code/08.gui/lvgl_transplant_spd2010/main/CMakeLists.txt new file mode 100644 index 0000000..cf2c455 --- /dev/null +++ b/code/08.gui/lvgl_transplant_spd2010/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS ".") diff --git a/code/08.gui/lvgl_transplant_spd2010/main/idf_component.yml b/code/08.gui/lvgl_transplant_spd2010/main/idf_component.yml new file mode 100644 index 0000000..6529be1 --- /dev/null +++ b/code/08.gui/lvgl_transplant_spd2010/main/idf_component.yml @@ -0,0 +1,19 @@ +## IDF Component Manager Manifest File +dependencies: + lvgl/lvgl: "^8.3.11" + espressif/esp_lcd_spd2010: "*" + espressif/esp_lcd_touch_spd2010: "^0.0.1" + ## Required IDF version + idf: + version: ">=4.1.0" + # # Put list of dependencies here + # # For components maintained by Espressif: + # component: "~1.0.0" + # # For 3rd party components: + # username/component: ">=1.0.0,<2.0.0" + # username2/component2: + # version: "~1.0.0" + # # For transient dependencies `public` flag can be set. + # # `public` flag doesn't have an effect dependencies of the `main` component. + # # All dependencies of `main` are public by default. + # public: true diff --git a/code/08.gui/lvgl_transplant_spd2010/main/main.c b/code/08.gui/lvgl_transplant_spd2010/main/main.c new file mode 100644 index 0000000..113d3df --- /dev/null +++ b/code/08.gui/lvgl_transplant_spd2010/main/main.c @@ -0,0 +1,408 @@ +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "driver/gpio.h" +#include "driver/i2c.h" +#include "driver/spi_master.h" +#include "esp_timer.h" +#include "esp_lcd_panel_io.h" +#include "esp_lcd_panel_vendor.h" +#include "esp_lcd_panel_ops.h" +#include "esp_err.h" +#include "esp_log.h" + +#include "lvgl.h" +#include "lv_demos.h" +#include "esp_lcd_spd2010.h" +#include "esp_lcd_touch_spd2010.h" + + +static const char *TAG = "main"; +static SemaphoreHandle_t lvgl_mux = NULL; + +// LCD和触摸控制器配置 +#define LCD_HOST SPI2_HOST +#define TOUCH_HOST I2C_NUM_0 + + +// 颜色深度 +#define LCD_BIT_PER_PIXEL (16) + +// 引脚配置 +// ESP Board SPD1020 Panel (QSPI) +// ┌──────────────────────┐ ┌────────────────────┐ +// │ GND ├─────────────►│ GND │ +// │ │ │ │ +// │ 3V3 ├─────────────►│ VCC │ +// │ │ │ │ +// │ CS ├─────────────►│ CS │ +// │ │ │ │ +// │ SCK ├─────────────►│ CLK │ +// │ │ │ │ +// │ D3 ├─────────────►│ IO3 │ +// │ │ │ │ +// │ D2 ├─────────────►│ IO2 │ +// │ │ │ │ +// │ D1 ├─────────────►│ IO1 │ +// │ │ │ │ +// │ D0 ├─────────────►│ IO0 │ +// │ │ │ │ +// │ RST ├─────────────►│ RSTN │ +// │ │ │ │ +// │ (SCL) ├─────────────►│ TP_SCL │ +// │ │ │ │ +// │ (SDA) ├─────────────►│ TP_SDA │ +// │ │ │ │ +// │ (TP_INT) ├─────────────►│ TP_INT │ +// │ │ │ │ +// │ (3V3) ├─────────────►│ TP_RST │ +// │ │ │ │ +// └──────────────────────┘ └────────────────────┘ +#define EXAMPLE_LCD_BK_LIGHT_ON_LEVEL 0 +#define EXAMPLE_LCD_BK_LIGHT_OFF_LEVEL !EXAMPLE_LCD_BK_LIGHT_ON_LEVEL +#define EXAMPLE_PIN_NUM_LCD_CS (GPIO_NUM_9) +#define EXAMPLE_PIN_NUM_LCD_PCLK (GPIO_NUM_10) +#define EXAMPLE_PIN_NUM_LCD_DATA0 (GPIO_NUM_11) +#define EXAMPLE_PIN_NUM_LCD_DATA1 (GPIO_NUM_12) +#define EXAMPLE_PIN_NUM_LCD_DATA2 (GPIO_NUM_13) +#define EXAMPLE_PIN_NUM_LCD_DATA3 (GPIO_NUM_14) +#define EXAMPLE_PIN_NUM_LCD_RST (GPIO_NUM_4) +#define EXAMPLE_PIN_NUM_BK_LIGHT (GPIO_NUM_3) + +// 触摸引脚配置 +#define EXAMPLE_PIN_NUM_TOUCH_SCL (GPIO_NUM_18) +#define EXAMPLE_PIN_NUM_TOUCH_SDA (GPIO_NUM_8) +#define EXAMPLE_PIN_NUM_TOUCH_RST (GPIO_NUM_7) +#define EXAMPLE_PIN_NUM_TOUCH_INT (GPIO_NUM_17) + +esp_lcd_touch_handle_t tp = NULL; + + +// LCD分辨率 +#define EXAMPLE_LCD_H_RES 412 +#define EXAMPLE_LCD_V_RES 412 + +// LVGLtask配置 +#define EXAMPLE_LVGL_TICK_PERIOD_MS 2 +#define EXAMPLE_LVGL_TASK_MAX_DELAY_MS 500 +#define EXAMPLE_LVGL_TASK_MIN_DELAY_MS 1 +#define EXAMPLE_LVGL_TASK_STACK_SIZE (4 * 1024) +#define EXAMPLE_LVGL_TASK_PRIORITY 2 + +static bool example_notify_lvgl_flush_ready(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx) +{ + lv_disp_drv_t *disp_driver = (lv_disp_drv_t *)user_ctx; + lv_disp_flush_ready(disp_driver); + return false; +} + + +static void example_lvgl_flush_cb(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_map) +{ + esp_lcd_panel_handle_t panel_handle = (esp_lcd_panel_handle_t) drv->user_data; + const int offsetx1 = area->x1; + const int offsetx2 = area->x2; + const int offsety1 = area->y1; + const int offsety2 = area->y2; + + // copy a buffer's content to a specific area of the display + esp_lcd_panel_draw_bitmap(panel_handle, offsetx1, offsety1, offsetx2 + 1, offsety2 + 1, color_map); +} + +/* Rotate display and touch, when rotated screen in LVGL. Called when driver parameters are updated. */ +static void example_lvgl_update_cb(lv_disp_drv_t *drv) +{ + esp_lcd_panel_handle_t panel_handle = (esp_lcd_panel_handle_t) drv->user_data; + + switch (drv->rotated) { + case LV_DISP_ROT_NONE: + // Rotate LCD display + esp_lcd_panel_swap_xy(panel_handle, false); + esp_lcd_panel_mirror(panel_handle, true, false); + // Rotate LCD touch + esp_lcd_touch_set_mirror_y(tp, false); + esp_lcd_touch_set_mirror_x(tp, false); + break; + case LV_DISP_ROT_90: + // Rotate LCD display + esp_lcd_panel_swap_xy(panel_handle, true); + esp_lcd_panel_mirror(panel_handle, true, true); + // Rotate LCD touch + esp_lcd_touch_set_mirror_y(tp, false); + esp_lcd_touch_set_mirror_x(tp, false); + break; + case LV_DISP_ROT_180: + // Rotate LCD display + esp_lcd_panel_swap_xy(panel_handle, false); + esp_lcd_panel_mirror(panel_handle, false, true); + // Rotate LCD touch + esp_lcd_touch_set_mirror_y(tp, false); + esp_lcd_touch_set_mirror_x(tp, false); + + break; + case LV_DISP_ROT_270: + // Rotate LCD display + esp_lcd_panel_swap_xy(panel_handle, true); + esp_lcd_panel_mirror(panel_handle, false, false); + // Rotate LCD touch + esp_lcd_touch_set_mirror_y(tp, false); + esp_lcd_touch_set_mirror_x(tp, false); + break; + } +} + +void example_lvgl_rounder_cb(struct _lv_disp_drv_t *disp_drv, lv_area_t *area) +{ + uint16_t x1 = area->x1; + uint16_t x2 = area->x2; + // round the start of coordinate down to the nearest 4M number + area->x1 = (x1 >> 2) << 2; + // round the end of coordinate up to the nearest 4N+3 number + area->x2 = ((x2 >> 2) << 2) + 3; +} + + +// 触屏信号量 +static SemaphoreHandle_t touch_mux = NULL; +// lvgl触摸回调函数 +static void example_lvgl_touch_cb(lv_indev_drv_t *drv, lv_indev_data_t *data) +{ + esp_lcd_touch_handle_t tp = (esp_lcd_touch_handle_t)drv->user_data; + assert(tp); + + uint16_t tp_x; + uint16_t tp_y; + uint8_t tp_cnt = 0; + /* Read data from touch controller into memory */ + if (xSemaphoreTake(touch_mux, 0) == pdTRUE) { + esp_lcd_touch_read_data(tp); + } + + /* Read data from touch controller */ + bool tp_pressed = esp_lcd_touch_get_coordinates(tp, &tp_x, &tp_y, NULL, &tp_cnt, 1); + if (tp_pressed && tp_cnt > 0) { + data->point.x = tp_x; + data->point.y = tp_y; + data->state = LV_INDEV_STATE_PRESSED; + ESP_LOGI(TAG, "Touch position: %d,%d", tp_x, tp_y); + } else { + data->state = LV_INDEV_STATE_RELEASED; + } +} + +static void example_touch_isr_cb(esp_lcd_touch_handle_t tp) +{ + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + xSemaphoreGiveFromISR(touch_mux, &xHigherPriorityTaskWoken); + + if (xHigherPriorityTaskWoken) { + portYIELD_FROM_ISR(); + } +} + + +// LVGL任务 +static void example_increase_lvgl_tick(void *arg) +{ + /* Tell LVGL how many milliseconds has elapsed */ + lv_tick_inc(EXAMPLE_LVGL_TICK_PERIOD_MS); +} + +static bool example_lvgl_lock(int timeout_ms) +{ + assert(lvgl_mux && "bsp_display_start must be called first"); + + const TickType_t timeout_ticks = (timeout_ms == -1) ? portMAX_DELAY : pdMS_TO_TICKS(timeout_ms); + return xSemaphoreTake(lvgl_mux, timeout_ticks) == pdTRUE; +} + +static void example_lvgl_unlock(void) +{ + assert(lvgl_mux && "bsp_display_start must be called first"); + xSemaphoreGive(lvgl_mux); +} + + +// LVGL任务 +static void example_lvgl_port_task(void *arg) +{ + ESP_LOGI(TAG, "Starting LVGL task"); + uint32_t task_delay_ms = EXAMPLE_LVGL_TASK_MAX_DELAY_MS; + while (1) { + ESP_LOGI(TAG, "LVGL task"); + // Lock the mutex due to the LVGL APIs are not thread-safe + if (example_lvgl_lock(-1)) { + task_delay_ms = lv_timer_handler(); + // Release the mutex + example_lvgl_unlock(); + } + if (task_delay_ms > EXAMPLE_LVGL_TASK_MAX_DELAY_MS) { + task_delay_ms = EXAMPLE_LVGL_TASK_MAX_DELAY_MS; + } else if (task_delay_ms < EXAMPLE_LVGL_TASK_MIN_DELAY_MS) { + task_delay_ms = EXAMPLE_LVGL_TASK_MIN_DELAY_MS; + } + vTaskDelay(pdMS_TO_TICKS(task_delay_ms)); + } +} + +void app_main(void) +{ + static lv_disp_draw_buf_t disp_buf; // contains internal graphic buffer(s) called draw buffer(s) + static lv_disp_drv_t disp_drv; // contains callback functions + + // 背光引脚配置 + ESP_LOGI(TAG, "Turn off LCD backlight"); + gpio_config_t bk_gpio_config = { + .mode = GPIO_MODE_OUTPUT, + .pin_bit_mask = 1ULL << EXAMPLE_PIN_NUM_BK_LIGHT + }; + ESP_ERROR_CHECK(gpio_config(&bk_gpio_config)); + + ESP_LOGI(TAG, "Initialize SPI bus"); + const spi_bus_config_t buscfg = SPD2010_PANEL_BUS_QSPI_CONFIG(EXAMPLE_PIN_NUM_LCD_PCLK, + EXAMPLE_PIN_NUM_LCD_DATA0, + EXAMPLE_PIN_NUM_LCD_DATA1, + EXAMPLE_PIN_NUM_LCD_DATA2, + EXAMPLE_PIN_NUM_LCD_DATA3, + EXAMPLE_LCD_H_RES * EXAMPLE_LCD_V_RES * LCD_BIT_PER_PIXEL / 8); + + ESP_ERROR_CHECK(spi_bus_initialize(LCD_HOST, &buscfg, SPI_DMA_CH_AUTO)); + + ESP_LOGI(TAG, "Install panel IO"); + esp_lcd_panel_io_handle_t io_handle = NULL; + const esp_lcd_panel_io_spi_config_t io_config = SPD2010_PANEL_IO_QSPI_CONFIG(EXAMPLE_PIN_NUM_LCD_CS, + example_notify_lvgl_flush_ready, + &disp_drv); + spd2010_vendor_config_t vendor_config = { + .flags = { + .use_qspi_interface = 1, + }, + }; + + // Attach the LCD to the SPI bus + ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)LCD_HOST, &io_config, &io_handle)); + + esp_lcd_panel_handle_t panel_handle = NULL; + const esp_lcd_panel_dev_config_t panel_config = { + .reset_gpio_num = EXAMPLE_PIN_NUM_LCD_RST, + .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB, + .bits_per_pixel = LCD_BIT_PER_PIXEL, + .vendor_config = &vendor_config, + }; + ESP_LOGI(TAG, "Install SPD2010 panel driver"); + ESP_ERROR_CHECK(esp_lcd_new_panel_spd2010(io_handle, &panel_config, &panel_handle)); + + + ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle)); + ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle)); + // user can flush pre-defined pattern to the screen before we turn on the screen or backlight + ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true)); + + // 初始化I2C总线 + touch_mux = xSemaphoreCreateBinary(); + assert(touch_mux); + + ESP_LOGI(TAG, "Initialize I2C bus"); + const i2c_config_t i2c_conf = { + .mode = I2C_MODE_MASTER, + .sda_io_num = EXAMPLE_PIN_NUM_TOUCH_SDA, + .sda_pullup_en = GPIO_PULLUP_ENABLE, + .scl_io_num = EXAMPLE_PIN_NUM_TOUCH_SCL, + .scl_pullup_en = GPIO_PULLUP_ENABLE, + .master.clk_speed = 400 * 1000, + }; + ESP_ERROR_CHECK(i2c_param_config(TOUCH_HOST, &i2c_conf)); + ESP_ERROR_CHECK(i2c_driver_install(TOUCH_HOST, i2c_conf.mode, 0, 0, 0)); + + // 触屏驱动IO句柄 + esp_lcd_panel_io_handle_t tp_io_handle = NULL; + const esp_lcd_panel_io_i2c_config_t tp_io_config = ESP_LCD_TOUCH_IO_I2C_SPD2010_CONFIG(); + + const esp_lcd_touch_config_t tp_cfg = { + .x_max = EXAMPLE_LCD_H_RES, + .y_max = EXAMPLE_LCD_V_RES, + .rst_gpio_num = EXAMPLE_PIN_NUM_TOUCH_RST, + .int_gpio_num = EXAMPLE_PIN_NUM_TOUCH_INT, + .levels = { + .reset = 0, + .interrupt = 0, + }, + .flags = { + .swap_xy = 0, + .mirror_x = 0, + .mirror_y = 0, + }, + .interrupt_callback = example_touch_isr_cb, + }; + + // Attach the TOUCH to the I2C bus + ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t)TOUCH_HOST, &tp_io_config, &tp_io_handle)); + + // 初始化触摸驱动 + ESP_LOGI(TAG, "Initialize touch controller SPD2010"); + ESP_ERROR_CHECK(esp_lcd_touch_new_i2c_spd2010(tp_io_handle, &tp_cfg, &tp)); + + // 打开背光 + ESP_LOGI(TAG, "Turn on LCD backlight"); + gpio_set_level(EXAMPLE_PIN_NUM_BK_LIGHT, EXAMPLE_LCD_BK_LIGHT_ON_LEVEL); + + // 初始化LVGL + ESP_LOGI(TAG, "Initialize LVGL library"); + lv_init(); + // alloc draw buffers used by LVGL + // it's recommended to choose the size of the draw buffer(s) to be at least 1/10 screen sized + lv_color_t *buf1 = heap_caps_malloc(EXAMPLE_LCD_H_RES * 10 * sizeof(lv_color_t), MALLOC_CAP_DMA); + assert(buf1); + lv_color_t *buf2 = heap_caps_malloc(EXAMPLE_LCD_H_RES * 10 * sizeof(lv_color_t), MALLOC_CAP_DMA); + assert(buf2); + // initialize LVGL draw buffers + lv_disp_draw_buf_init(&disp_buf, buf1, buf2, EXAMPLE_LCD_H_RES * 10); + + ESP_LOGI(TAG, "Register display driver to LVGL"); + lv_disp_drv_init(&disp_drv); + disp_drv.hor_res = EXAMPLE_LCD_H_RES; + disp_drv.ver_res = EXAMPLE_LCD_V_RES; + disp_drv.flush_cb = example_lvgl_flush_cb; + disp_drv.rounder_cb = example_lvgl_rounder_cb; + disp_drv.drv_update_cb = example_lvgl_update_cb; + disp_drv.draw_buf = &disp_buf; + disp_drv.user_data = panel_handle; + lv_disp_t *disp = lv_disp_drv_register(&disp_drv); + + ESP_LOGI(TAG, "Install LVGL tick timer"); + // Tick interface for LVGL (using esp_timer to generate 2ms periodic event) + const esp_timer_create_args_t lvgl_tick_timer_args = { + .callback = &example_increase_lvgl_tick, + .name = "lvgl_tick" + }; + esp_timer_handle_t lvgl_tick_timer = NULL; + ESP_ERROR_CHECK(esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer)); + ESP_ERROR_CHECK(esp_timer_start_periodic(lvgl_tick_timer, EXAMPLE_LVGL_TICK_PERIOD_MS * 1000)); + + static lv_indev_drv_t indev_drv; // Input device driver (Touch) + lv_indev_drv_init(&indev_drv); + indev_drv.type = LV_INDEV_TYPE_POINTER; + indev_drv.disp = disp; + indev_drv.read_cb = example_lvgl_touch_cb; + indev_drv.user_data = tp; + + lv_indev_drv_register(&indev_drv); + + + lvgl_mux = xSemaphoreCreateMutex(); + assert(lvgl_mux); + xTaskCreate(example_lvgl_port_task, "LVGL", EXAMPLE_LVGL_TASK_STACK_SIZE, NULL, EXAMPLE_LVGL_TASK_PRIORITY, NULL); + + ESP_LOGI(TAG, "Display LVGL demos"); + // Lock the mutex due to the LVGL APIs are not thread-safe + if (example_lvgl_lock(-1)) { + lv_demo_widgets(); /* A widgets example */ + //lv_demo_music(); /* A modern, smartphone-like music player demo. */ + // lv_demo_stress(); /* A stress test for LVGL. */ + // lv_demo_benchmark(); /* A demo to measure the performance of LVGL or to compare different settings. */ + + // Release the mutex + example_lvgl_unlock(); + } +} + diff --git a/code/08.gui/lvgl_transplant_spd2010/partitions.csv b/code/08.gui/lvgl_transplant_spd2010/partitions.csv new file mode 100644 index 0000000..57bcbf0 --- /dev/null +++ b/code/08.gui/lvgl_transplant_spd2010/partitions.csv @@ -0,0 +1,5 @@ +# Name, Type, SubType, Offset, Size, Flags +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap +nvs, data, nvs, 0x10000, 0x6000, +phy_init, data, phy, , 0x1000, +factory, app, factory, , 0x2c0000,