diff --git a/main/APP/app_task_hello/app_task_hello.c b/main/APP/app_task_hello/app_task_hello.c
new file mode 100644
index 0000000..c819087
--- /dev/null
+++ b/main/APP/app_task_hello/app_task_hello.c
@@ -0,0 +1,43 @@
+/**
+ * @file app_task_hello.c
+ * @author impressionyang (impressionyang@outlook.com)
+ * @brief
+ * @version 0.1
+ * @date 2022-09-28
+ * _ _
+ * (_)_ _ ___ _______ ___ ___ (_)__ ___ __ _____ ____ ___ _
+ * / / ' \/ _ \/ __/ -_|_-<(_- / _ \/ _ \/ // / _ `/ _ \/ _ `/
+ * /_/_/_/_/ .__/_/ \__/___/___/_/\___/_//_/\_, /\_,_/_//_/\_, /
+ * /_/ /___/ /___/
+ * @copyright Copyright (c) 2022 impressionyang
+ *
+ * @par 修改日志:
+ *
+ * | Date | Version | Author | Description
+ * |
|---|
| 2022-09-28 | v1.0 | impressionyang | 内容
+ * |
+ */
+#include "app_task_hello.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+
+static void _app_hello_task_run(void *param)
+{
+ uint16_t idx = 0;
+ while(1) {
+ printf("hello %d\r\n", idx++);
+ vTaskDelay(100);
+ }
+}
+
+uint8_t app_hello_task_start()
+{
+ vTaskDelay(10);
+ xTaskCreatePinnedToCore(_app_hello_task_run, "hello task", 4096, NULL, 5, NULL, tskNO_AFFINITY);
+ return 0;
+}
+
+uint8_t app_hello_task_stop()
+{
+ return 0;
+}
diff --git a/main/APP/app_task_hello/app_task_hello.h b/main/APP/app_task_hello/app_task_hello.h
new file mode 100644
index 0000000..8825e45
--- /dev/null
+++ b/main/APP/app_task_hello/app_task_hello.h
@@ -0,0 +1,52 @@
+/**
+ * @file app_hello_task.h
+ * @author impressionyang (impressionyang@outlook.com)
+ * @brief
+ * @version 0.1
+ * @date 2022-09-28
+ * _ _
+ * (_)_ _ ___ _______ ___ ___ (_)__ ___ __ _____ ____ ___ _
+ * / / ' \/ _ \/ __/ -_|_-<(_- / _ \/ _ \/ // / _ `/ _ \/ _ `/
+ * /_/_/_/_/ .__/_/ \__/___/___/_/\___/_//_/\_, /\_,_/_//_/\_, /
+ * /_/ /___/ /___/
+ * @copyright Copyright (c) 2022 impressionyang
+ *
+ * @par 修改日志:
+ *
+ * | Date | Version | Author | Description
+ * |
|---|
| 2022-09-28 | v1.0 | impressionyang | 内容
+ * |
+ */
+#ifndef __APP_HELLO_TASK_H__
+#define __APP_HELLO_TASK_H__
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ *
+ * @brief
+ * @author impressionyang (impressionyang@outlook.com)
+ * @return uint8_t
+ *
+ * @details
+ */
+uint8_t app_hello_task_start();
+
+/**
+ *
+ * @brief
+ * @author impressionyang (impressionyang@outlook.com)
+ * @return uint8_t
+ *
+ * @details
+ */
+uint8_t app_hello_task_stop();
+
+#ifdef __cplusplus
+}
+#endif
+#endif//__APP_HELLO_TASK_H__
\ No newline at end of file
diff --git a/main/APP/app_task_mqtt/app_task_mqtt.c b/main/APP/app_task_mqtt/app_task_mqtt.c
new file mode 100644
index 0000000..682bad4
--- /dev/null
+++ b/main/APP/app_task_mqtt/app_task_mqtt.c
@@ -0,0 +1,177 @@
+/**
+ * @file app_task_mqtt.c
+ * @author impressionyang (impressionyang@outlook.com)
+ * @brief
+ * @version 0.1
+ * @date 2022-09-29
+ * _ _
+ * (_)_ _ ___ _______ ___ ___ (_)__ ___ __ _____ ____ ___ _
+ * / / ' \/ _ \/ __/ -_|_-<(_- / _ \/ _ \/ // / _ `/ _ \/ _ `/
+ * /_/_/_/_/ .__/_/ \__/___/___/_/\___/_//_/\_, /\_,_/_//_/\_, /
+ * /_/ /___/ /___/
+ * @copyright Copyright (c) 2022 impressionyang
+ *
+ * @par 修改日志:
+ *
+ * | Date | Version | Author | Description
+ * |
|---|
| 2022-09-29 | v1.0 | impressionyang | 内容
+ * |
+ */
+#include "app_task_mqtt.h"
+#include "app_main.h"
+
+#include
+#include
+#include
+#include
+#include "esp_wifi.h"
+#include "esp_system.h"
+#include "nvs_flash.h"
+#include "esp_event_loop.h"
+
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/semphr.h"
+#include "freertos/queue.h"
+#include "freertos/event_groups.h"
+
+#include "lwip/sockets.h"
+#include "lwip/dns.h"
+#include "lwip/netdb.h"
+
+#include "esp_log.h"
+#include "mqtt_client.h"
+
+static const char *TAG = "MQTT_EXAMPLE";
+//mqtt连上事件
+static EventGroupHandle_t mqtt_event_group;
+const static int CONNECTED_BIT = BIT0;
+esp_mqtt_client_handle_t client;
+
+static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event)
+{
+ esp_mqtt_client_handle_t client = event->client;
+ int msg_id;
+ // your_context_t *context = event->context;
+ switch (event->event_id) {
+ case MQTT_EVENT_CONNECTED://MQTT连上事件
+ ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
+ xEventGroupSetBits(mqtt_event_group, CONNECTED_BIT);
+ //发布主题
+ // 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;
+ case MQTT_EVENT_DISCONNECTED://MQTT断开连接事件
+ ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
+ //mqtt连上事件
+ xEventGroupClearBits(mqtt_event_group, CONNECTED_BIT);
+ break;
+
+ case MQTT_EVENT_SUBSCRIBED://MQTT发送订阅事件
+ ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
+ msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "订阅成功", 0, 0, 0);
+ ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
+ break;
+ case MQTT_EVENT_UNSUBSCRIBED://MQTT取消订阅事件
+ ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
+ break;
+ case MQTT_EVENT_PUBLISHED://MQTT发布事件
+ ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
+ break;
+ case MQTT_EVENT_DATA://MQTT接受数据事件
+ 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;
+ case MQTT_EVENT_ERROR://MQTT错误事件
+ ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
+ xEventGroupClearBits(mqtt_event_group, CONNECTED_BIT);
+ break;
+ default:
+ break;
+ }
+ return ESP_OK;
+}
+
+//mqtt初始化
+static void mqtt_app_start(void)
+{
+ mqtt_event_group = xEventGroupCreate();
+ esp_mqtt_client_config_t mqtt_cfg = {
+ .host = "117.50.172.12", //MQTT服务器IP
+ .event_handle = mqtt_event_handler, //MQTT事件
+ .port=21883, //端口
+ .username = "admin", //用户名
+ .password = "public", //密码
+ // .user_context = (void *)your_context
+ };
+
+#if CONFIG_BROKER_URL_FROM_STDIN
+ char line[128];
+
+ if (strcmp(mqtt_cfg.uri, "FROM_STDIN") == 0) {
+ int count = 0;
+ printf("Please enter url of mqtt broker\n");
+ while (count < 128) {
+ int c = fgetc(stdin);
+ if (c == '\n') {
+ line[count] = '\0';
+ break;
+ } else if (c > 0 && c < 127) {
+ line[count] = c;
+ ++count;
+ }
+ vTaskDelay(10 / portTICK_PERIOD_MS);
+ }
+ mqtt_cfg.uri = line;
+ printf("Broker url: %s\n", line);
+ } else {
+ ESP_LOGE(TAG, "Configuration mismatch: wrong broker url");
+ abort();
+ }
+#endif /* CONFIG_BROKER_URL_FROM_STDIN */
+
+ client = esp_mqtt_client_init(&mqtt_cfg);
+ esp_mqtt_client_start(client);
+ //等mqtt连上
+ xEventGroupWaitBits(mqtt_event_group, CONNECTED_BIT, false, true, portMAX_DELAY);
+}
+
+extern double g_temp;
+extern double g_pres;
+
+static void _app_task_mqtt_run(void* param)
+{
+ while (!app_main_handle_get_nework_state()) {
+ vTaskDelay(10);
+ }
+ ESP_ERROR_CHECK(esp_netif_init());
+ mqtt_app_start();
+ char buf[50] = {0};
+ while (1) {
+ vTaskDelay(1000);
+ sprintf(buf, "temp = %.4lf, presure = %.4lf\r\n", g_temp, g_pres);
+ esp_mqtt_client_publish(client, "/topic/bmp280", buf, 0, 0, 0);
+ }
+}
+
+uint8_t app_task_mqtt_start()
+{
+ vTaskDelay(10);
+ xTaskCreatePinnedToCore(_app_task_mqtt_run, "mqtt app task", 4096, NULL, 5, NULL, tskNO_AFFINITY);
+ return 0;
+}
+
+uint8_t app_task_mqtt_stop()
+{
+ return 0;
+}
diff --git a/main/APP/app_task_mqtt/app_task_mqtt.h b/main/APP/app_task_mqtt/app_task_mqtt.h
new file mode 100644
index 0000000..25b60a0
--- /dev/null
+++ b/main/APP/app_task_mqtt/app_task_mqtt.h
@@ -0,0 +1,52 @@
+/**
+ * @file app_task_mqtt.h
+ * @author impressionyang (impressionyang@outlook.com)
+ * @brief
+ * @version 0.1
+ * @date 2022-09-29
+ * _ _
+ * (_)_ _ ___ _______ ___ ___ (_)__ ___ __ _____ ____ ___ _
+ * / / ' \/ _ \/ __/ -_|_-<(_- / _ \/ _ \/ // / _ `/ _ \/ _ `/
+ * /_/_/_/_/ .__/_/ \__/___/___/_/\___/_//_/\_, /\_,_/_//_/\_, /
+ * /_/ /___/ /___/
+ * @copyright Copyright (c) 2022 impressionyang
+ *
+ * @par 修改日志:
+ *
+ * | Date | Version | Author | Description
+ * |
|---|
| 2022-09-29 | v1.0 | impressionyang | 内容
+ * |
+ */
+#ifndef __APP_TASK_MQTT_H__
+#define __APP_TASK_MQTT_H__
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ *
+ * @brief
+ * @author impressionyang (impressionyang@outlook.com)
+ * @return uint8_t
+ *
+ * @details
+ */
+uint8_t app_task_mqtt_stop();
+
+/**
+ *
+ * @brief
+ * @author impressionyang (impressionyang@outlook.com)
+ * @return uint8_t
+ *
+ * @details
+ */
+uint8_t app_task_mqtt_start();
+
+#ifdef __cplusplus
+}
+#endif
+#endif//__APP_TASK_MQTT_H__
\ No newline at end of file
diff --git a/main/APP/app_task_sensors/app_task_sensors.c b/main/APP/app_task_sensors/app_task_sensors.c
new file mode 100644
index 0000000..fa1b22c
--- /dev/null
+++ b/main/APP/app_task_sensors/app_task_sensors.c
@@ -0,0 +1,152 @@
+#include "app_task_sensors.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "driver/i2c.h"
+
+#include "drv_bmp280_3v3.h"
+#include
+#include
+#include
+
+#include "shell_port.h"
+#include "msg_queue.h"
+
+#define SENSOR_DRV_I2C_MASTER_SCL_IO 33
+#define SENSOR_DRV_I2C_MASTER_SDA_IO 34
+#define SENSOR_DRV_I2C_MASTER_FREQ_HZ 100000
+#define SENSOR_DRV_I2C_CONTROLLER_PORT 0
+#define SENSOR_DRV_I2C_MASTER_TIMEOUT_MS 1000
+#define SENSOR_DRV_I2C_MASTER_RX_BUF_DISABLE 0
+#define SENSOR_DRV_I2C_MASTER_TX_BUF_DISABLE 0
+
+static i2c_config_t sg_drv_sensor_i2c_conf = {
+ .mode = I2C_MODE_MASTER,
+ .sda_io_num = SENSOR_DRV_I2C_MASTER_SDA_IO,
+ .scl_io_num = SENSOR_DRV_I2C_MASTER_SCL_IO,
+ .sda_pullup_en = GPIO_PULLUP_ENABLE,
+ .scl_pullup_en = GPIO_PULLUP_ENABLE,
+ .master.clk_speed = SENSOR_DRV_I2C_MASTER_FREQ_HZ,
+};
+
+static drv_bmp280_3v3_t* sg_drv_bmp280_handle = NULL;
+double g_temp = 0;
+double g_pres = 0;
+
+static int8_t drv_i2c_read(uint8_t reg_addr, uint8_t *data, uint32_t data_len, void *chip_addr)
+{
+ int ret = i2c_master_write_read_device(SENSOR_DRV_I2C_CONTROLLER_PORT, *((uint8_t*)chip_addr) , ®_addr, 1, data, data_len, SENSOR_DRV_I2C_MASTER_TIMEOUT_MS / portTICK_RATE_MS);
+
+ if (ret) {
+ printf("I2C read error = %d, chip addr = %02x\r\n", ret, *((uint8_t*)chip_addr));
+ }
+ return 0;
+}
+
+static int8_t drv_i2c_write(uint8_t reg_addr, const uint8_t *data, uint32_t data_len, void *chip_addr)
+{
+ int ret, i;
+ uint8_t write_buf[51] = {0}; //{reg_addr, *data};
+
+ if (data_len > 50 || data_len == 0) {
+ return 1;
+ }
+ write_buf[0] = reg_addr;
+ for (i = 0 ; i < data_len; i++) {
+ write_buf[i+1] = data[i];
+ }
+
+ ret = i2c_master_write_to_device(SENSOR_DRV_I2C_CONTROLLER_PORT, *((uint8_t*)chip_addr), write_buf, data_len + 1, SENSOR_DRV_I2C_MASTER_TIMEOUT_MS / portTICK_RATE_MS);
+
+ if (ret) {
+ printf("I2C write error = %d\r\n", ret);
+ }
+ return 0;
+}
+
+static void drv_delay_ms_fptr_t(uint32_t period, void *intf_ptr)
+{
+ vTaskDelay(1);
+}
+
+static uint8_t _app_task_sensors_drv_init()
+{
+ sg_drv_bmp280_handle = malloc(sizeof(drv_bmp280_3v3_t));
+ memset(sg_drv_bmp280_handle, 0, sizeof(drv_bmp280_3v3_t));
+ sg_drv_bmp280_handle->drv_i2c_read = drv_i2c_read;
+ sg_drv_bmp280_handle->drv_i2c_write = drv_i2c_write;
+ sg_drv_bmp280_handle->delay_10ms = drv_delay_ms_fptr_t;
+ drv_bmp280_3v3_init(sg_drv_bmp280_handle);
+ return 0;
+}
+
+static uint8_t _app_task_sensors_drv_deinit()
+{
+
+ return 0;
+}
+
+static esp_err_t _app_task_sensors_esp_i2c_init()
+{
+ i2c_param_config(SENSOR_DRV_I2C_CONTROLLER_PORT, &sg_drv_sensor_i2c_conf);
+
+ return i2c_driver_install(SENSOR_DRV_I2C_CONTROLLER_PORT, sg_drv_sensor_i2c_conf.mode, SENSOR_DRV_I2C_MASTER_RX_BUF_DISABLE, SENSOR_DRV_I2C_MASTER_TX_BUF_DISABLE, 0);
+}
+
+static void _app_task_sensors_run()
+{
+ int ret = 0;
+ uint32_t presure = 0;
+ msg_data_t msg_data = {0};
+ ret = _app_task_sensors_esp_i2c_init();
+ if (ret) {
+ printf("sensor i2c init faild = %d\r\n", ret);
+ return;
+ }
+
+ _app_task_sensors_drv_init();
+
+ while(1) {
+
+ ret = drv_bmp280_3v3_refresh_data(sg_drv_bmp280_handle);
+ if (!ret) {
+ ret = drv_bmp280_3v3_get_tempreture(sg_drv_bmp280_handle, &g_temp);
+ // printf("temp = %.4lf\r\n", temp);
+ ret = drv_bmp280_3v3_get_pressure(sg_drv_bmp280_handle, &g_pres);
+ // printf("pres = %.4lf\r\n", pres);
+ }else {
+ printf("bmp280 is mesuring\r\n");
+ }
+ msg_data.msg_type = 1;
+ msg_data.msg_id = 0;
+ msg_data.msg_value = (uint16_t)g_temp;
+ msg_queue_send_msg("mqtt_task", &msg_data);
+
+ vTaskDelay(100);
+ }
+}
+
+uint8_t app_task_sensors_start()
+{
+ vTaskDelay(10);
+ xTaskCreatePinnedToCore(_app_task_sensors_run, "sensor task", 4096, NULL, 4, NULL, tskNO_AFFINITY);
+ return 0;
+}
+
+uint8_t app_task_sensors_stop()
+{
+ return 0;
+}
+
+static void _show_bmp280(int argc, char **argv)
+{
+ int ret = 0;
+ ret = drv_bmp280_3v3_get_tempreture(sg_drv_bmp280_handle, &g_temp);
+ ret = drv_bmp280_3v3_get_pressure(sg_drv_bmp280_handle, &g_pres);
+ printf("temp = %.4lf\r\n", g_temp);
+ printf("pres = %.4lf\r\n", g_pres);
+
+}
+
+SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), show_bmp280, _show_bmp280, show bmp280 pressure and tempreture);
+
+
diff --git a/main/APP/app_task_sensors/app_task_sensors.h b/main/APP/app_task_sensors/app_task_sensors.h
new file mode 100644
index 0000000..dcef346
--- /dev/null
+++ b/main/APP/app_task_sensors/app_task_sensors.h
@@ -0,0 +1,17 @@
+#ifndef __APP_TASK_SENSORS_H__
+#define __APP_TASK_SENSORS_H__
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+uint8_t app_task_sensors_start();
+
+uint8_t app_task_sensors_stop();
+
+#ifdef __cplusplus
+}
+#endif
+#endif//__APP_TASK_SENSORS_H__
\ No newline at end of file
diff --git a/main/APP/app_task_wifi/app_task_wifi.c b/main/APP/app_task_wifi/app_task_wifi.c
new file mode 100644
index 0000000..b2144ac
--- /dev/null
+++ b/main/APP/app_task_wifi/app_task_wifi.c
@@ -0,0 +1,148 @@
+/**
+ * @file app_task_wifi.c
+ * @author impressionyang (impressionyang@outlook.com)
+ * @brief
+ * @version 0.1
+ * @date 2022-09-29
+ * _ _
+ * (_)_ _ ___ _______ ___ ___ (_)__ ___ __ _____ ____ ___ _
+ * / / ' \/ _ \/ __/ -_|_-<(_- / _ \/ _ \/ // / _ `/ _ \/ _ `/
+ * /_/_/_/_/ .__/_/ \__/___/___/_/\___/_//_/\_, /\_,_/_//_/\_, /
+ * /_/ /___/ /___/
+ * @copyright Copyright (c) 2022 impressionyang
+ *
+ * @par 修改日志:
+ *
+ * | Date | Version | Author | Description
+ * |
|---|
| 2022-09-29 | v1.0 | impressionyang | 内容
+ * |
+ */
+#include "app_task_wifi.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/event_groups.h"
+#include "esp_wifi.h"
+#include "esp_log.h"
+#include "esp_event.h"
+#include
+
+/* Set the SSID and Password via project configuration, or can set directly here */
+#define DEFAULT_SSID "1022"
+#define DEFAULT_PWD "w15077040648"
+
+#if CONFIG_EXAMPLE_WIFI_ALL_CHANNEL_SCAN
+#define DEFAULT_SCAN_METHOD WIFI_ALL_CHANNEL_SCAN
+#elif CONFIG_EXAMPLE_WIFI_FAST_SCAN
+#define DEFAULT_SCAN_METHOD WIFI_FAST_SCAN
+#else
+#define DEFAULT_SCAN_METHOD WIFI_FAST_SCAN
+#endif /*CONFIG_EXAMPLE_SCAN_METHOD*/
+
+#if CONFIG_EXAMPLE_WIFI_CONNECT_AP_BY_SIGNAL
+#define DEFAULT_SORT_METHOD WIFI_CONNECT_AP_BY_SIGNAL
+#elif CONFIG_EXAMPLE_WIFI_CONNECT_AP_BY_SECURITY
+#define DEFAULT_SORT_METHOD WIFI_CONNECT_AP_BY_SECURITY
+#else
+#define DEFAULT_SORT_METHOD WIFI_CONNECT_AP_BY_SIGNAL
+#endif /*CONFIG_EXAMPLE_SORT_METHOD*/
+
+#if CONFIG_EXAMPLE_FAST_SCAN_THRESHOLD
+#define DEFAULT_RSSI CONFIG_EXAMPLE_FAST_SCAN_MINIMUM_SIGNAL
+#if CONFIG_EXAMPLE_FAST_SCAN_WEAKEST_AUTHMODE_OPEN
+#define DEFAULT_AUTHMODE WIFI_AUTH_OPEN
+#elif CONFIG_EXAMPLE_FAST_SCAN_WEAKEST_AUTHMODE_WEP
+#define DEFAULT_AUTHMODE WIFI_AUTH_WEP
+#elif CONFIG_EXAMPLE_FAST_SCAN_WEAKEST_AUTHMODE_WPA
+#define DEFAULT_AUTHMODE WIFI_AUTH_WPA_PSK
+#elif CONFIG_EXAMPLE_FAST_SCAN_WEAKEST_AUTHMODE_WPA2
+#define DEFAULT_AUTHMODE WIFI_AUTH_WPA2_PSK
+#else
+#define DEFAULT_AUTHMODE WIFI_AUTH_OPEN
+#endif
+#else
+#define DEFAULT_RSSI -127
+#define DEFAULT_AUTHMODE WIFI_AUTH_OPEN
+#endif /*CONFIG_EXAMPLE_FAST_SCAN_THRESHOLD*/
+
+static const char *TAG = "scan";
+static app_task_wifi_t sg_wifi_app_handle = {0};
+
+static void event_handler(void* arg, esp_event_base_t event_base,
+ int32_t event_id, void* event_data)
+{
+ if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
+ esp_wifi_connect();
+ } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
+ esp_wifi_connect();
+ } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
+ ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
+ ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
+ }
+}
+
+
+/* Initialize Wi-Fi as sta and set scan method */
+static void fast_scan(void)
+{
+ tcpip_adapter_init();
+ 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_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL, NULL));
+ ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL, NULL));
+
+ // Initialize default station as network interface instance (esp-netif)
+ esp_netif_t *sta_netif = esp_netif_create_default_wifi_sta();
+ assert(sta_netif);
+
+ // Initialize and start WiFi
+ wifi_config_t wifi_config = {
+ .sta = {
+ .ssid = DEFAULT_SSID,
+ .password = DEFAULT_PWD,
+ .scan_method = DEFAULT_SCAN_METHOD,
+ .sort_method = DEFAULT_SORT_METHOD,
+ .threshold.rssi = DEFAULT_RSSI,
+ .threshold.authmode = DEFAULT_AUTHMODE,
+ },
+ };
+ ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
+ ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
+ ESP_ERROR_CHECK(esp_wifi_start());
+}
+
+static void _app_wifi_task_run(void *param)
+{
+ fast_scan();
+ while(sg_wifi_app_handle.is_wifi_app_running) {
+ // printf("wifi info:\r\n");
+ // printf("is wifi conneted : %d\r\n", sg_wifi_app_handle.is_wifi_conneted);
+ vTaskDelay(100);
+ sg_wifi_app_handle.is_wifi_conneted = 1;
+ }
+}
+
+uint8_t app_task_wifi_start()
+{
+ vTaskDelay(10);
+ sg_wifi_app_handle.is_wifi_app_start = 1;
+ sg_wifi_app_handle.is_wifi_app_running = 1;
+
+ xTaskCreatePinnedToCore(_app_wifi_task_run, "wifi app task", 4096, NULL, 5, NULL, tskNO_AFFINITY);
+ return 0;
+}
+
+uint8_t app_task_wifi_stop()
+{
+ sg_wifi_app_handle.is_wifi_app_running = 0;
+ return 0;
+}
+
+uint8_t app_task_wifi_get_info(app_task_wifi_t *info_ptr)
+{
+ memcpy(info_ptr, &sg_wifi_app_handle, sizeof(app_task_wifi_t));
+ return 0;
+}
\ No newline at end of file
diff --git a/main/APP/app_task_wifi/app_task_wifi.h b/main/APP/app_task_wifi/app_task_wifi.h
new file mode 100644
index 0000000..ac2098b
--- /dev/null
+++ b/main/APP/app_task_wifi/app_task_wifi.h
@@ -0,0 +1,74 @@
+/**
+ * @file app_task_wifi.h
+ * @author impressionyang (impressionyang@outlook.com)
+ * @brief
+ * @version 0.1
+ * @date 2022-09-29
+ * _ _
+ * (_)_ _ ___ _______ ___ ___ (_)__ ___ __ _____ ____ ___ _
+ * / / ' \/ _ \/ __/ -_|_-<(_- / _ \/ _ \/ // / _ `/ _ \/ _ `/
+ * /_/_/_/_/ .__/_/ \__/___/___/_/\___/_//_/\_, /\_,_/_//_/\_, /
+ * /_/ /___/ /___/
+ * @copyright Copyright (c) 2022 impressionyang
+ *
+ * @par 修改日志:
+ *
+ * | Date | Version | Author | Description
+ * |
|---|
| 2022-09-29 | v1.0 | impressionyang | 内容
+ * |
+ */
+#ifndef __APP_TASK_WIFI_H__
+#define __APP_TASK_WIFI_H__
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/// @brief wifi 控制句柄
+typedef struct _app_task_wifi_t_
+{
+ /// @brief wifi APP是否启动:0-》未启动 | 1-》已经启动
+ uint8_t is_wifi_app_start;
+ /// @brief wifi是否连接:0-》未连接 | 1-》已连接
+ uint8_t is_wifi_conneted;
+ /// @brief wifi APP线程是否运行:0-》未运行 | 1-》正在运行
+ uint8_t is_wifi_app_running;
+} app_task_wifi_t;
+
+/**
+ * app_task_wifi_start
+ * @brief wifi APP启动
+ * @author impressionyang (impressionyang@outlook.com)
+ * @return uint8_t
+ *
+ * @details
+ */
+uint8_t app_task_wifi_start();
+
+/**
+ * app_task_wifi_stop
+ * @brief wifi APP关闭
+ * @author impressionyang (impressionyang@outlook.com)
+ * @return uint8_t
+ *
+ * @details
+ */
+uint8_t app_task_wifi_stop();
+
+/**
+ * app_task_wifi_get_info
+ * @brief wifi APP信息获取
+ * @author impressionyang (impressionyang@outlook.com)
+ * @param [in] info_ptr
+ * @return uint8_t
+ *
+ * @details
+ */
+uint8_t app_task_wifi_get_info(app_task_wifi_t *info_ptr);
+
+#ifdef __cplusplus
+}
+#endif
+#endif//__APP_TASK_WIFI_H__
\ No newline at end of file
diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt
index 0488bd1..985efda 100644
--- a/main/CMakeLists.txt
+++ b/main/CMakeLists.txt
@@ -1,2 +1,36 @@
-idf_component_register(SRCS "real_time_stats_example_main.c"
- INCLUDE_DIRS ".")
+# (utilities/letter_shell/port/esp-idf)
+
+
+
+idf_component_register(
+ SRC_DIRS
+ "."
+ "APP/app_task_hello"
+ # "APP/app_task_wifi"
+ # "APP/app_task_mqtt"
+ # "APP/app_task_sensors"
+ # "drivers/drv_bmp280_3v3"
+ # "drivers/msg_queue"
+ # "drivers/drv_bmp280_3v3/bmp2"
+ "drivers/st7789"
+ "drivers/cst816"
+ "utilities/letter_shell/src"
+ "utilities/letter_shell/port/esp-idf"
+ # "utilities/link_list"
+ INCLUDE_DIRS
+ "."
+ "APP/app_task_hello"
+ # "APP/app_task_wifi"
+ # "APP/app_task_mqtt"
+ # "APP/app_task_sensors"
+ # "drivers/drv_bmp280_3v3"
+ # "drivers/msg_queue"
+ # "drivers/drv_bmp280_3v3/bmp2"
+ "drivers/st7789"
+ "drivers/cst816"
+ "utilities/letter_shell/src"
+ "utilities/letter_shell/port/esp-idf"
+ # "utilities/link_list"
+ LDFRAGMENTS
+ "utilities/letter_shell/port/esp-idf/shell.lf"
+)
diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild
new file mode 100644
index 0000000..fd0c10e
--- /dev/null
+++ b/main/Kconfig.projbuild
@@ -0,0 +1,139 @@
+menu "ST7789 Configuration"
+
+ config GPIO_RANGE_MAX
+ int
+ default 33 if IDF_TARGET_ESP32
+ default 46 if IDF_TARGET_ESP32S2
+ default 19 if IDF_TARGET_ESP32C3
+ default 48 if IDF_TARGET_ESP32S3
+
+ config WIDTH
+ int "SCREEN WIDTH"
+ range 0 999
+ default 240
+ help
+ The width resolution of the screen.
+
+ config HEIGHT
+ int "SCREEN HEIGHT"
+ range 0 999
+ default 240
+ help
+ The height resolution of the screen.
+
+ config OFFSETX
+ int "GRAM X OFFSET"
+ range 0 99
+ default 0
+ help
+ When your TFT have offset(X), set it.
+
+ config OFFSETY
+ int "GRAM Y OFFSET"
+ range 0 99
+ default 0
+ help
+ When your TFT have offset(Y), set it.
+
+ config MOSI_GPIO
+ int "MOSI GPIO number"
+ range 0 GPIO_RANGE_MAX
+ default 23 if IDF_TARGET_ESP32
+ default 35 if IDF_TARGET_ESP32S2
+ default 35 if IDF_TARGET_ESP32S3
+ default 0 if IDF_TARGET_ESP32C3
+ help
+ GPIO number (IOxx) to SPI MOSI.
+ Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to MOSI.
+ On the ESP32, GPIOs 35-39 are input-only so cannot be used as outputs.
+ On the ESP32-S2, GPIO 46 is input-only so cannot be used as outputs.
+
+ config SCLK_GPIO
+ int "SCLK GPIO number"
+ range 0 GPIO_RANGE_MAX
+ default 18 if IDF_TARGET_ESP32
+ default 36 if IDF_TARGET_ESP32S2
+ default 36 if IDF_TARGET_ESP32S3
+ default 1 if IDF_TARGET_ESP32C3
+ help
+ GPIO number (IOxx) to SPI SCLK.
+ Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to SCLK.
+ On the ESP32, GPIOs 35-39 are input-only so cannot be used as outputs.
+ On the ESP32-S2, GPIO 46 is input-only so cannot be used as outputs.
+
+ config CS_GPIO
+ int "CS GPIO number"
+ range -1 GPIO_RANGE_MAX
+ default -1 if IDF_TARGET_ESP32
+ default -1 if IDF_TARGET_ESP32S2
+ default -1 if IDF_TARGET_ESP32S3
+ default -1 if IDF_TARGET_ESP32C3
+ help
+ GPIO number (IOxx) to SPI CS.
+ When it is -1, CS isn't performed.
+ Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to CS.
+ On the ESP32, GPIOs 35-39 are input-only so cannot be used as outputs.
+ On the ESP32-S2, GPIO 46 is input-only so cannot be used as outputs.
+
+ config DC_GPIO
+ int "DC GPIO number"
+ range 0 GPIO_RANGE_MAX
+ default 27 if IDF_TARGET_ESP32
+ default 37 if IDF_TARGET_ESP32S2
+ default 40 if IDF_TARGET_ESP32S3
+ default 2 if IDF_TARGET_ESP32C3
+ help
+ GPIO number (IOxx) to SPI DC.
+ Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to DC.
+ On the ESP32, GPIOs 35-39 are input-only so cannot be used as outputs.
+ On the ESP32-S2, GPIO 46 is input-only so cannot be used as outputs.
+
+ config RESET_GPIO
+ int "RESET GPIO number"
+ range 0 GPIO_RANGE_MAX
+ default 33 if IDF_TARGET_ESP32
+ default 38 if IDF_TARGET_ESP32S2
+ default 41 if IDF_TARGET_ESP32S3
+ default 3 if IDF_TARGET_ESP32C3
+ help
+ GPIO number (IOxx) to RESET.
+ Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to RESET.
+ On the ESP32, GPIOs 35-39 are input-only so cannot be used as outputs.
+ On the ESP32-S2, GPIO 46 is input-only so cannot be used as outputs.
+
+ config BL_GPIO
+ int "BACKLIGHT GPIO number"
+ range -1 GPIO_RANGE_MAX
+ default 32 if IDF_TARGET_ESP32
+ default 33 if IDF_TARGET_ESP32S2
+ default 33 if IDF_TARGET_ESP32S3
+ default 4 if IDF_TARGET_ESP32C3
+ help
+ GPIO number (IOxx) to BACKLIGHT.
+ When it is -1, BACKLIGHT isn't performed.
+ Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to BACKLIGHT.
+ On the ESP32, GPIOs 35-39 are input-only so cannot be used as outputs.
+ On the ESP32-S2, GPIO 46 is input-only so cannot be used as outputs.
+
+ config INVERSION
+ bool "Enable Display Inversion"
+ default false
+ help
+ Enable Display Inversion.
+
+ choice SPI_HOST
+ prompt "SPI peripheral that controls this bus"
+ default SPI2_HOST
+ help
+ Select SPI peripheral that controls this bus.
+ config SPI2_HOST
+ bool "SPI2_HOST"
+ help
+ Use SPI2_HOST. This is also called HSPI_HOST.
+ config SPI3_HOST
+ bool "SPI3_HOST"
+ help
+ USE SPI3_HOST. This is also called VSPI_HOST
+ endchoice
+
+endmenu
diff --git a/main/app_main.c b/main/app_main.c
new file mode 100644
index 0000000..4d9114b
--- /dev/null
+++ b/main/app_main.c
@@ -0,0 +1,192 @@
+/* Hello World 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 "sdkconfig.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "esp_system.h"
+#include "esp_spi_flash.h"
+#include "nvs_flash.h"
+#include "esp_err.h"
+#include "esp_log.h"
+
+#include "app_task_hello.h"
+// #include "app_task_wifi.h"
+// #include "app_task_mqtt.h"
+// #include "app_task_sensors.h"
+#include "st7789.h"
+#include "CST816T.h"
+#include "app_main.h"
+#include "shell_port.h"
+// #include "msg_queue.h"
+
+static app_main_handle_t sg_app_main_handle = {0};
+
+static void _init_esp()
+{
+ // 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 );
+}
+
+TickType_t FillTest(TFT_t * dev, int width, int height) {
+ TickType_t startTick, endTick, diffTick;
+ startTick = xTaskGetTickCount();
+
+ lcdFillScreen(dev, RED);
+ vTaskDelay(50);
+ lcdFillScreen(dev, GREEN);
+ vTaskDelay(50);
+ lcdFillScreen(dev, BLUE);
+ vTaskDelay(50);
+
+ endTick = xTaskGetTickCount();
+ diffTick = endTick - startTick;
+ ESP_LOGI(__FUNCTION__, "elapsed time[ms]:%d",diffTick*portTICK_PERIOD_MS);
+ return diffTick;
+}
+
+void cst_scan_gesture()
+{
+ while (1)
+ {
+ vTaskDelay(1);
+ if (cst816t_available())
+ {
+ /*printf("gesture.id %u \n", data.gestureID);
+ printf("points %u \n", data.points);
+ printf("event %u \n", data.event);*/
+ printf("x %i \n", data.x);
+ printf("y %i \n", data.y);
+
+ switch (data.gestureID)
+ {
+ case NONE:
+ // printf("NONE");
+ break;
+ case SWIPE_DOWN:
+ printf("SWIPE DOWN \n");
+ break;
+ case SWIPE_UP:
+ printf("SWIPE UP \n");
+ break;
+ case SWIPE_LEFT:
+ printf("SWIPE LEFT \n");
+ break;
+ case SWIPE_RIGHT:
+ printf("SWIPE RIGHT \n");
+ break;
+ case SINGLE_CLICK:
+ printf("SINGLE CLICK \n");
+ break;
+ case DOUBLE_CLICK:
+ printf("DOUBLE CLICK \n");
+ break;
+ case LONG_PRESS:
+ printf("LONG PRESS \n");
+ break;
+ default:
+ printf("UNKNOWN \n");
+ break;
+ }
+ }
+ }
+}
+
+void app_main(void)
+{
+ // app_task_wifi_t wifi_info = {0};
+ // msg_queue_init();
+ printf("Hello world!\n");
+
+ vTaskDelay(10);
+
+ _init_esp();
+ // app_hello_task_start();
+ // app_task_wifi_start();
+ // app_task_mqtt_start();
+ // app_task_sensors_start();
+
+ userShellInit();
+
+ cst816t_begin(34, 33, 35, 36);
+
+ xTaskCreatePinnedToCore(cst_scan_gesture, "sct test", 4096, NULL, 4, NULL, tskNO_AFFINITY);
+
+
+ TFT_t dev;
+ spi_master_init(&dev, CONFIG_MOSI_GPIO, CONFIG_SCLK_GPIO, CONFIG_CS_GPIO, CONFIG_DC_GPIO, CONFIG_RESET_GPIO, CONFIG_BL_GPIO);
+ // lcdBacklightOn(&dev);
+ // vTaskDelay(1000);
+ lcdInit(&dev, CONFIG_WIDTH, CONFIG_HEIGHT, CONFIG_OFFSETX, CONFIG_OFFSETY);
+ // lcdBacklightOn(&dev);
+
+#if CONFIG_INVERSION
+ // ESP_LOGI(TAG, "Enable Display Inversion");
+ lcdInversionOn(&dev);
+#endif
+
+ /* Print chip information */
+ esp_chip_info_t chip_info;
+ esp_chip_info(&chip_info);
+ printf("This is %s chip with %d CPU core(s), WiFi%s%s, ",
+ CONFIG_IDF_TARGET,
+ chip_info.cores,
+ (chip_info.features & CHIP_FEATURE_BT) ? "/BT" : "",
+ (chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : "");
+
+ printf("silicon revision %d, ", chip_info.revision);
+
+ printf("%dMB %s flash\n", spi_flash_get_chip_size() / (1024 * 1024),
+ (chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external");
+
+ printf("Minimum free heap size: %d bytes\n", esp_get_minimum_free_heap_size());
+
+ // uint8_t ret = msg_queue_create("mqtt_task");
+ // printf("ret = %d\r\n", ret);
+
+ // msg_data_t msg_data = {0};
+ for (int i = 10; ; ) {
+ // printf("Restarting in %d seconds...\n", i);
+ // app_task_wifi_get_info(&wifi_info);
+ // sg_app_main_handle.have_network = wifi_info.is_wifi_conneted;
+ FillTest(&dev, CONFIG_WIDTH, CONFIG_HEIGHT);
+ vTaskDelay(5000 / portTICK_PERIOD_MS);
+ // if (!msg_queue_recive_msg("mqtt_task", &msg_data, 100)) {
+ // printf("msg queue get data = %d\r\n", msg_data.msg_type);
+ // }
+ }
+ printf("Restarting now.\n");
+ fflush(stdout);
+ esp_restart();
+}
+
+uint8_t app_main_handle_get_nework_state()
+{
+ return sg_app_main_handle.have_network;
+}
+
+static void _show_build_time(int argc, char **argv)
+{
+ printf("build at %s %s\n", __DATE__, __TIME__);
+}
+
+SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), show_build_time, _show_build_time, show the build time);
+
+static void _reboot(int argc, char **argv)
+{
+ esp_restart();
+}
+
+SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), reboot, _reboot, reboot system);
+
diff --git a/main/app_main.h b/main/app_main.h
new file mode 100644
index 0000000..aff189e
--- /dev/null
+++ b/main/app_main.h
@@ -0,0 +1,48 @@
+/**
+ * @file app_main.h
+ * @author impressionyang (impressionyang@outlook.com)
+ * @brief
+ * @version 0.1
+ * @date 2022-09-29
+ * _ _
+ * (_)_ _ ___ _______ ___ ___ (_)__ ___ __ _____ ____ ___ _
+ * / / ' \/ _ \/ __/ -_|_-<(_- / _ \/ _ \/ // / _ `/ _ \/ _ `/
+ * /_/_/_/_/ .__/_/ \__/___/___/_/\___/_//_/\_, /\_,_/_//_/\_, /
+ * /_/ /___/ /___/
+ * @copyright Copyright (c) 2022 impressionyang
+ *
+ * @par 修改日志:
+ *
+ * | Date | Version | Author | Description
+ * |
|---|
| 2022-09-29 | v1.0 | impressionyang | 内容
+ * |
+ */
+#ifndef __APP_MAIN_H__
+#define __APP_MAIN_H__
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _app_main_handle_
+{
+ uint8_t have_network;
+} app_main_handle_t;
+
+
+/**
+ *
+ * @brief 获取网络连接状态
+ * @author impressionyang (impressionyang@outlook.com)
+ * @return uint8_t
+ *
+ * @details
+ */
+uint8_t app_main_handle_get_nework_state();
+
+#ifdef __cplusplus
+}
+#endif
+#endif//__APP_MAIN_H__
\ No newline at end of file
diff --git a/main/drivers/cst816/CST816T.c b/main/drivers/cst816/CST816T.c
new file mode 100644
index 0000000..8ce43e9
--- /dev/null
+++ b/main/drivers/cst816/CST816T.c
@@ -0,0 +1,113 @@
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include "esp_log.h"
+#include "esp_system.h"
+#include "driver/i2c.h"
+#include "driver/gpio.h"
+#include "CST816T.h"
+
+static const char *TAG = "CST816T ";
+
+static int i2c_master_port = I2C_MASTER_NUM;
+
+esp_err_t i2c_master_init(void)
+{
+
+ i2c_config_t conf = {
+ .mode = I2C_MODE_MASTER,
+ .sda_io_num = _sda,
+ .scl_io_num = _scl,
+ .sda_pullup_en = GPIO_PULLUP_ENABLE,
+ .scl_pullup_en = GPIO_PULLUP_ENABLE,
+ .master.clk_speed = I2C_MASTER_FREQ_HZ,
+ };
+ i2c_param_config(i2c_master_port, &conf);
+ return i2c_driver_install(i2c_master_port, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0);
+}
+
+void cst816t_read_touch()
+{
+ uint8_t rx_data[6];
+ uint8_t tx_data[5];
+ tx_data[0] = 0x01;
+ i2c_master_write_to_device(i2c_master_port, CST816T_ADDRESS, tx_data, 1, I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
+ vTaskDelay(50 / portTICK_RATE_MS);
+ i2c_master_read_from_device(i2c_master_port, CST816T_ADDRESS, rx_data, 6, I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
+ // ESP_LOG_BUFFER_HEX(TAG, rx_data, 6);
+ vTaskDelay(50 / portTICK_RATE_MS);
+ data.gestureID = rx_data[0];
+ data.points = rx_data[1];
+ data.event = rx_data[2] >> 6;
+ data.x = rx_data[3];
+ data.y = rx_data[5];
+}
+
+void IRAM_ATTR gpioHandler(void *arg)
+{
+ _event_available = true;
+}
+
+void cst816t_begin(int sda, int scl, int rst, int irq)
+{
+ _sda = sda;
+ _scl = scl;
+ _rst = rst;
+ _irq = irq;
+ ESP_ERROR_CHECK(i2c_master_init());
+ gpio_pad_select_gpio(_rst);
+ gpio_set_direction(_rst, GPIO_MODE_OUTPUT);
+ gpio_pad_select_gpio(_irq);
+ gpio_set_direction(_irq, GPIO_MODE_INPUT);
+
+ gpio_set_level(_rst, 1);
+ vTaskDelay(50 / portTICK_RATE_MS);
+ gpio_set_level(_rst, 0);
+ vTaskDelay(5 / portTICK_RATE_MS);
+ gpio_set_level(_rst, 1);
+ vTaskDelay(50 / portTICK_RATE_MS);
+
+ uint8_t rx_data[5];
+ uint8_t tx_data[5];
+ // 芯片性能检查
+ tx_data[0] = 0x15;
+ ESP_LOGE(TAG, "tx_data = 0x15");
+ i2c_master_write_to_device(i2c_master_port, CST816T_ADDRESS, tx_data, 1, I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
+ vTaskDelay(50 / portTICK_RATE_MS);
+ i2c_master_read_from_device(i2c_master_port, CST816T_ADDRESS, rx_data, 1, I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
+ ESP_LOG_BUFFER_HEX(TAG, rx_data, 1);
+ vTaskDelay(50 / portTICK_RATE_MS);
+ //验证芯片版本
+ tx_data[0] = 0xA7;
+ ESP_LOGE(TAG, "tx_data = 0xA7");
+ i2c_master_write_to_device(i2c_master_port, CST816T_ADDRESS, tx_data, 1, I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
+ vTaskDelay(50 / portTICK_RATE_MS);
+ i2c_master_read_from_device(i2c_master_port, CST816T_ADDRESS, rx_data, 3, I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
+ ESP_LOG_BUFFER_HEX(TAG, rx_data, 3);
+ vTaskDelay(50 / portTICK_RATE_MS);
+ //设置和初始化中断
+ gpio_install_isr_service(0);
+ gpio_set_intr_type(_irq, GPIO_INTR_NEGEDGE);
+ gpio_isr_handler_add(_irq, gpioHandler, (void *)_irq);
+ gpio_intr_enable(_irq);
+}
+
+bool cst816t_available()
+{
+ if (_event_available)
+ {
+ cst816t_read_touch();
+ _event_available = false;
+ return true;
+ }
+ else
+ {
+ vTaskDelay(1);
+ }
+ return false;
+}
\ No newline at end of file
diff --git a/main/drivers/cst816/CST816T.h b/main/drivers/cst816/CST816T.h
new file mode 100644
index 0000000..5940ce3
--- /dev/null
+++ b/main/drivers/cst816/CST816T.h
@@ -0,0 +1,50 @@
+#ifndef __CST816T_H__
+#define __CST816T_H__
+#define I2C_MASTER_NUM 1 /*!< I2C master i2c port number, the number of i2c peripheral interfaces available will depend on the chip */
+#define I2C_MASTER_FREQ_HZ 400000 /*!< 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 */
+#define I2C_MASTER_TIMEOUT_MS 1000
+#define CST816T_ADDRESS 0x15
+#define CST816T_RESET_BIT 8
+#define CST816T_RAW_DATA_SIZE 8
+
+typedef struct data_struct
+{
+ uint8_t gestureID; // Gesture ID
+ uint8_t points; // Number of touch points
+ uint8_t event; // Event (0 = Down, 1 = Up, 2 = Contact)
+ int x;
+ int y;
+ uint8_t version;
+ uint8_t versionInfo[3];
+} data_struct_t;
+
+typedef enum GESTURE
+{
+ NONE = 0x00,
+ SWIPE_UP = 0x01,
+ SWIPE_DOWN = 0x02,
+ SWIPE_LEFT = 0x04,
+ SWIPE_RIGHT = 0x03,
+ SINGLE_CLICK = 0x05,
+ DOUBLE_CLICK = 0x0B,
+ LONG_PRESS = 0x0C
+
+} gesture_t;
+
+int _sda;
+int _scl;
+int _rst;
+int _irq;
+
+void cst816t_begin(int sda, int scl, int rst, int irq);
+bool cst816t_available();
+void cst816t_read_touch();
+bool _event_available;
+void IRAM_ATTR gpioHandler(void *arg);
+esp_err_t i2c_master_init(void);
+data_struct_t data;
+// String gesture();
+
+#endif
\ No newline at end of file
diff --git a/main/drivers/drv_bmp280_3v3/bmp2/bmp2.c b/main/drivers/drv_bmp280_3v3/bmp2/bmp2.c
new file mode 100644
index 0000000..e9917fd
--- /dev/null
+++ b/main/drivers/drv_bmp280_3v3/bmp2/bmp2.c
@@ -0,0 +1,1032 @@
+/**
+* Copyright (c) 2021 Bosch Sensortec GmbH. All rights reserved.
+*
+* BSD-3-Clause
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+*
+* 1. Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+*
+* 2. Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution.
+*
+* 3. Neither the name of the copyright holder nor the names of its
+* contributors may be used to endorse or promote products derived from
+* this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+* POSSIBILITY OF SUCH DAMAGE.
+*
+* @file bmp2.c
+* @date 2021-05-21
+* @version v1.0.1
+*
+*/
+
+/*! @file bmp2.c
+ * @brief Sensor driver for BMP2 sensor
+ */
+
+#include "bmp2.h"
+
+/********************** Static function declarations ************************/
+
+/*!
+ * @brief This internal API is used to check for null-pointers in the device
+ * structure.
+ *
+ * @param[in] dev : Structure instance of bmp2_dev.
+ *
+ * @return Result of API execution status
+ * @retval 0 -> Success
+ * @retval <0 -> Fail
+ */
+static int8_t null_ptr_check(const struct bmp2_dev *dev);
+
+/*!
+ * @brief This internal API interleaves the register addresses and respective
+ * register data for a burst write
+ *
+ * @param[in] reg_addr : Register address array
+ * @param[out] temp_buff : Interleaved register address and data array
+ * @param[in] reg_data : Register data array
+ * @param[in] len : Length of the reg_addr and reg_data arrays
+ *
+ */
+static void interleave_data(const uint8_t *reg_addr, uint8_t *temp_buff, const uint8_t *reg_data, uint32_t len);
+
+/*!
+ * @brief This API is used to read the calibration parameters used
+ * for calculating the compensated data.
+ *
+ * @param[in] dev : Structure instance of bmp2_dev
+ *
+ * @return Result of API execution status
+ * @retval 0 -> Success
+ * @retval <0 -> Fail
+ */
+static int8_t get_calib_param(struct bmp2_dev *dev);
+
+/*!
+ * @brief This internal API to reset the sensor, restore/set conf, restore/set mode
+ *
+ * @param[in] mode : Desired mode
+ * @param[in] conf : Desired configuration to the bmp2
+ *
+ * conf->os_mode = BMP2_OS_MODE_ULTRA_LOW_POWER, BMP2_OS_MODE_LOW_POWER, BMP2_OS_MODE_STANDARD_RESOLUTION,
+ * BMP2_OS_MODE_HIGH_RESOLUTION, BMP2_OS_MODE_ULTRA_HIGH_RESOLUTION
+ *
+ * conf->mode = BMP2_POWERMODE_SLEEP, BMP2_POWERMODE_FORCED, BMP2_POWERMODE_NORMAL
+ *
+ * conf->odr = BMP2_ODR_0_5_MS, BMP2_ODR_62_5_MS, BMP2_ODR_125_MS,
+ * BMP2_ODR_250_MS, BMP2_ODR_500_MS, BMP2_ODR_1000_MS,
+ * BMP2_ODR_2000_MS, BMP2_ODR_4000_MS
+ *
+ * conf->filter = BMP2_FILTER_OFF, BMP2_FILTER_COEFF_2,
+ * BMP2_FILTER_COEFF_4, BMP2_FILTER_COEFF_8, BMP2_FILTER_COEFF_16
+ *
+ * @param[in] dev : Structure instance of bmp2_dev
+ *
+ * @return Result of API execution status
+ * @retval 0 -> Success
+ * @retval <0 -> Fail
+ */
+static int8_t conf_sensor(uint8_t mode, const struct bmp2_config *conf, struct bmp2_dev *dev);
+
+/*!
+ * @brief This API is used to set the over-sampling rate of temperature and pressure
+ * based on the over-sampling mode.
+ *
+ * @param[in] reg_data : Contains register data
+ * @param[out] conf : Desired configuration to the bmp2
+ *
+ */
+static void set_os_mode(uint8_t *reg_data, const struct bmp2_config *conf);
+
+/*!
+ * @brief This API is used to parse the pressure and temperature
+ * data and store it in the bmp2_uncomp_data structure instance.
+ *
+ * @param[in] reg_data : Contains register data which needs to be parsed
+ * @param[out] uncomp_data : Contains the uncompensated pressure, temperature
+ *
+ * @return Result of API execution status
+ * @retval 0 -> Success
+ * @retval <0 -> Fail
+ */
+static int8_t parse_sensor_data(const uint8_t *reg_data, struct bmp2_uncomp_data *uncomp_data);
+
+#ifdef BMP2_DOUBLE_COMPENSATION
+
+/*!
+ * @brief This internal API is used to get the compensated temperature from
+ * uncompensated temperature. This API uses double floating precision.
+ *
+ * @param[out] comp_temperature : Compensated temperature data in double.
+ * @param[in] uncomp_data : Contains the uncompensated temperature data.
+ * @param[in] dev : Structure instance of bmp2_dev.
+ *
+ * @return Result of API execution status
+ * @retval 0 -> Success
+ * @retval >0 -> Warning
+ * @retval <0 -> Fail
+ */
+static int8_t compensate_temperature(double *comp_temperature,
+ const struct bmp2_uncomp_data *uncomp_data,
+ struct bmp2_dev *dev);
+
+/*!
+ * @brief This internal API is used to get the compensated pressure from
+ * uncompensated pressure. This API uses double floating precision.
+ *
+ * @param[out] comp_pressure : Compensated pressure data in double.
+ * @param[in] uncomp_data : Contains the uncompensated pressure data.
+ * @param[in] dev : Structure instance of bmp2_dev.
+ *
+ * @return Result of API execution status
+ * @retval 0 -> Success
+ * @retval >0 -> Warning
+ * @retval <0 -> Fail
+ */
+static int8_t compensate_pressure(double *comp_pressure,
+ const struct bmp2_uncomp_data *uncomp_data,
+ const struct bmp2_dev *dev);
+
+#else
+
+/*!
+ * @brief This internal API is used to get the compensated temperature from
+ * uncompensated temperature. This API uses 32bit integer data type.
+ *
+ * @param[out] comp_temperature : Compensated temperature data in integer.
+ * @param[in] uncomp_data : Contains the uncompensated temperature data.
+ * @param[in] dev : Structure instance of bmp2_dev.
+ *
+ * @return Result of API execution status
+ * @retval 0 -> Success
+ * @retval >0 -> Warning
+ * @retval <0 -> Fail
+ */
+static int8_t compensate_temperature(int32_t *comp_temperature,
+ const struct bmp2_uncomp_data *uncomp_data,
+ struct bmp2_dev *dev);
+
+/*!
+ * @brief This internal API is used to get the compensated pressure from
+ * uncompensated pressure. This API uses 64bit integer data type.
+ *
+ * @param[out] comp_pressure : Compensated pressure data in integer.
+ * @param[in] uncomp_data : Contains the uncompensated pressure data.
+ * @param[in] dev : Structure instance of bmp2_dev.
+ *
+ * @return Result of API execution status
+ * @retval 0 -> Success
+ * @retval >0 -> Warning
+ * @retval <0 -> Fail
+ */
+static int8_t compensate_pressure(uint32_t *comp_pressure,
+ const struct bmp2_uncomp_data *uncomp_data,
+ const struct bmp2_dev *dev);
+
+#endif
+
+/*!
+ * @This internal API checks whether the uncompensated temperature and pressure are within the range
+ *
+ * @param[in] utemperature : Uncompensated temperature
+ * @param[in] upressure : Uncompensated pressure
+ *
+ * @return Result of API execution status
+ * @retval 0 -> Success
+ * @retval <0 -> Fail
+ */
+static int8_t st_check_boundaries(int32_t utemperature, int32_t upressure);
+
+/****************** User Function Definitions *******************************/
+
+/*!
+ * @brief This API is the entry point.
+ * It reads the chip-id and calibration data from the sensor.
+ */
+int8_t bmp2_init(struct bmp2_dev *dev)
+{
+ int8_t rslt;
+
+ rslt = null_ptr_check(dev);
+
+ if (rslt == BMP2_OK)
+ {
+ rslt = bmp2_get_regs(BMP2_REG_CHIP_ID, &dev->chip_id, 1, dev);
+
+ /* Check for chip id validity */
+ if (rslt == BMP2_OK)
+ {
+ if (dev->chip_id == BMP2_CHIP_ID)
+ {
+ rslt = get_calib_param(dev);
+ }
+ else
+ {
+ rslt = BMP2_E_DEV_NOT_FOUND;
+ }
+ }
+ }
+
+ return rslt;
+}
+
+/*!
+ * @brief This API reads the data from the given register address of the
+ * sensor.
+ */
+int8_t bmp2_get_regs(uint8_t reg_addr, uint8_t *reg_data, uint32_t len, struct bmp2_dev *dev)
+{
+ int8_t rslt;
+
+ rslt = null_ptr_check(dev);
+
+ if ((rslt == BMP2_OK) && (reg_data != NULL))
+ {
+ /* Mask the register address' MSB if interface selected is SPI */
+ if (dev->intf == BMP2_SPI_INTF)
+ {
+ reg_addr = reg_addr | BMP2_SPI_RD_MASK;
+ }
+
+ dev->intf_rslt = dev->read(reg_addr, reg_data, len, dev->intf_ptr);
+
+ /* Check for communication error and mask with an internal error code */
+ if (dev->intf_rslt != BMP2_INTF_RET_SUCCESS)
+ {
+ rslt = BMP2_E_COM_FAIL;
+ }
+ }
+ else
+ {
+ rslt = BMP2_E_NULL_PTR;
+ }
+
+ return rslt;
+}
+
+/*!
+ * @brief This API writes the given data to the register addresses
+ * of the sensor.
+ */
+int8_t bmp2_set_regs(uint8_t *reg_addr, const uint8_t *reg_data, uint32_t len, struct bmp2_dev *dev)
+{
+ int8_t rslt;
+ uint8_t temp_buff[8]; /* Typically not to write more than 4 registers */
+ uint32_t temp_len;
+ uint8_t reg_addr_cnt;
+
+ if (len > BMP2_MAX_LEN)
+ {
+ len = BMP2_MAX_LEN;
+ }
+
+ rslt = null_ptr_check(dev);
+
+ if ((rslt == BMP2_OK) && (reg_addr != NULL) && (reg_data != NULL))
+ {
+ if (len > 0)
+ {
+ temp_buff[0] = reg_data[0];
+
+ /* Mask the register address' MSB if interface selected is SPI */
+ if (dev->intf == BMP2_SPI_INTF)
+ {
+ /* Converting all the reg address into proper SPI write address
+ * i.e making MSB(R/`W) bit 0
+ */
+ for (reg_addr_cnt = 0; reg_addr_cnt < len; reg_addr_cnt++)
+ {
+ reg_addr[reg_addr_cnt] = reg_addr[reg_addr_cnt] & BMP2_SPI_WR_MASK;
+ }
+ }
+
+ /* Burst write mode */
+ if (len > 1)
+ {
+ /* Interleave register address w.r.t data for burst write */
+ interleave_data(reg_addr, temp_buff, reg_data, len);
+ temp_len = ((len * 2) - 1);
+ }
+ else
+ {
+ temp_len = len;
+ }
+
+ dev->intf_rslt = dev->write(reg_addr[0], temp_buff, temp_len, dev->intf_ptr);
+
+ /* Check for communication error and mask with an internal error code */
+ if (dev->intf_rslt != BMP2_INTF_RET_SUCCESS)
+ {
+ rslt = BMP2_E_COM_FAIL;
+ }
+ }
+ else
+ {
+ rslt = BMP2_E_INVALID_LEN;
+ }
+ }
+ else
+ {
+ rslt = BMP2_E_NULL_PTR;
+ }
+
+ return rslt;
+}
+
+/*!
+ * @brief This API triggers the soft-reset of the sensor.
+ */
+int8_t bmp2_soft_reset(struct bmp2_dev *dev)
+{
+ int8_t rslt;
+ uint8_t reg_addr = BMP2_REG_SOFT_RESET;
+ uint8_t soft_rst_cmd = BMP2_SOFT_RESET_CMD;
+
+ rslt = bmp2_set_regs(®_addr, &soft_rst_cmd, 1, dev);
+
+ return rslt;
+}
+
+/*!
+ * @brief This API reads the data from the ctrl_meas register and config
+ * register. It gives the currently set temperature and pressure over-sampling
+ * configuration, power mode configuration, sleep duration and
+ * IIR filter coefficient.
+ */
+int8_t bmp2_get_config(struct bmp2_config *conf, struct bmp2_dev *dev)
+{
+ int8_t rslt;
+ uint8_t temp[2] = { 0, 0 };
+
+ if (conf != NULL)
+ {
+ rslt = bmp2_get_regs(BMP2_REG_CTRL_MEAS, temp, 2, dev);
+
+ if (rslt == BMP2_OK)
+ {
+ conf->os_temp = BMP2_GET_BITS(temp[0], BMP2_OS_TEMP);
+ conf->os_pres = BMP2_GET_BITS(temp[0], BMP2_OS_PRES);
+ conf->odr = BMP2_GET_BITS(temp[1], BMP2_STANDBY_DURN);
+ conf->filter = BMP2_GET_BITS(temp[1], BMP2_FILTER);
+ conf->spi3w_en = BMP2_GET_BITS_POS_0(temp[1], BMP2_SPI3_ENABLE);
+ }
+ }
+ else
+ {
+ rslt = BMP2_E_NULL_PTR;
+ }
+
+ return rslt;
+}
+
+/*!
+ * @brief This API writes the data to the ctrl_meas register and config register.
+ * It sets the over-sampling mode, power mode configuration,
+ * sleep duration and IIR filter coefficient.
+ */
+int8_t bmp2_set_config(const struct bmp2_config *conf, struct bmp2_dev *dev)
+{
+ return conf_sensor(BMP2_POWERMODE_SLEEP, conf, dev);
+}
+
+/*!
+ * @brief This API reads the status register
+ */
+int8_t bmp2_get_status(struct bmp2_status *status, struct bmp2_dev *dev)
+{
+ int8_t rslt;
+ uint8_t temp;
+
+ if (status != NULL)
+ {
+ rslt = bmp2_get_regs(BMP2_REG_STATUS, &temp, 1, dev);
+
+ if (rslt == BMP2_OK)
+ {
+ status->measuring = BMP2_GET_BITS(temp, BMP2_STATUS_MEAS);
+ status->im_update = BMP2_GET_BITS_POS_0(temp, BMP2_STATUS_IM_UPDATE);
+ }
+ }
+ else
+ {
+ rslt = BMP2_E_NULL_PTR;
+ }
+
+ return rslt;
+}
+
+/*!
+ * @brief This API reads the power mode.
+ */
+int8_t bmp2_get_power_mode(uint8_t *mode, struct bmp2_dev *dev)
+{
+ int8_t rslt;
+ uint8_t temp;
+
+ if (mode != NULL)
+ {
+ rslt = bmp2_get_regs(BMP2_REG_CTRL_MEAS, &temp, 1, dev);
+
+ *mode = BMP2_GET_BITS_POS_0(temp, BMP2_POWERMODE);
+ dev->power_mode = *mode;
+ }
+ else
+ {
+ rslt = BMP2_E_NULL_PTR;
+ }
+
+ return rslt;
+}
+
+/*!
+ * @brief This API writes the power mode.
+ */
+int8_t bmp2_set_power_mode(uint8_t mode, const struct bmp2_config *conf, struct bmp2_dev *dev)
+{
+ int8_t rslt;
+
+ rslt = conf_sensor(mode, conf, dev);
+
+ return rslt;
+}
+
+/*!
+ * @brief This API reads the pressure and temperature data from the
+ * sensor, compensates the data and store it in the bmp2_data structure
+ * instance passed by the user.
+ */
+int8_t bmp2_get_sensor_data(struct bmp2_data *comp_data, struct bmp2_dev *dev)
+{
+ int8_t rslt;
+ uint8_t temp[BMP2_P_T_LEN] = { 0 };
+ struct bmp2_uncomp_data uncomp_data = { 0 };
+
+ if (comp_data != NULL)
+ {
+ rslt = bmp2_get_regs(BMP2_REG_PRES_MSB, temp, BMP2_P_T_LEN, dev);
+
+ if (rslt == BMP2_OK)
+ {
+ /* Parse the read data from the sensor */
+ rslt = parse_sensor_data(temp, &uncomp_data);
+
+ if (rslt == BMP2_OK)
+ {
+ /* Compensate the pressure and/or temperature
+ * data from the sensor
+ */
+ rslt = bmp2_compensate_data(&uncomp_data, comp_data, dev);
+ }
+ }
+ }
+ else
+ {
+ rslt = BMP2_E_NULL_PTR;
+ }
+
+ return rslt;
+}
+
+/*!
+ * @brief This API is used to compensate the pressure and
+ * temperature data.
+ */
+int8_t bmp2_compensate_data(const struct bmp2_uncomp_data *uncomp_data,
+ struct bmp2_data *comp_data,
+ struct bmp2_dev *dev)
+{
+ int8_t rslt;
+
+ rslt = null_ptr_check(dev);
+
+ if ((rslt == BMP2_OK) && (uncomp_data != NULL) && (comp_data != NULL))
+ {
+ /* Initialize to zero */
+ comp_data->temperature = 0;
+ comp_data->pressure = 0;
+
+ rslt = compensate_temperature(&comp_data->temperature, uncomp_data, dev);
+
+ if (rslt == BMP2_OK)
+ {
+ rslt = compensate_pressure(&comp_data->pressure, uncomp_data, dev);
+ }
+ }
+ else
+ {
+ rslt = BMP2_E_NULL_PTR;
+ }
+
+ return rslt;
+}
+
+/*!
+ * @brief This API computes the measurement time in microseconds for the
+ * active configuration based on standbytime(conf->odr) and over-sampling mode(conf->os_mode)
+ */
+int8_t bmp2_compute_meas_time(uint32_t *sampling_time, const struct bmp2_config *conf, const struct bmp2_dev *dev)
+{
+ int8_t rslt;
+
+ /* Array contains measurement time in microseconds */
+ uint32_t measurement_time[] = { 5500, 7500, 11500, 19500, 37500 };
+ uint32_t standby_time[] = { 500, 62500, 125000, 250000, 500000, 1000000, 2000000, 4000000 };
+
+ rslt = null_ptr_check(dev);
+
+ if ((rslt == BMP2_OK) && (conf != NULL))
+ {
+ if (dev->power_mode == BMP2_POWERMODE_NORMAL)
+ {
+ /* Time in microseconds */
+ (*sampling_time) = measurement_time[conf->os_mode] + standby_time[conf->odr];
+ }
+ else
+ {
+ /* Time in microseconds */
+ (*sampling_time) = measurement_time[conf->os_mode];
+ }
+ }
+ else
+ {
+ rslt = BMP2_E_NULL_PTR;
+ }
+
+ return rslt;
+}
+
+/****************** Static Function Definitions *******************************/
+
+/*!
+ * @brief This internal API is used to check for null-pointers in the device
+ * structure.
+ */
+static int8_t null_ptr_check(const struct bmp2_dev *dev)
+{
+ int8_t rslt;
+
+ if ((dev == NULL) || (dev->read == NULL) || (dev->write == NULL) || (dev->delay_us == NULL))
+ {
+ /* Null-pointer found */
+ rslt = BMP2_E_NULL_PTR;
+ }
+ else
+ {
+ rslt = BMP2_OK;
+ }
+
+ return rslt;
+}
+
+/*!
+ * @brief This internal API interleaves the register addresses and respective
+ * register data for a burst write
+ */
+static void interleave_data(const uint8_t *reg_addr, uint8_t *temp_buff, const uint8_t *reg_data, uint32_t len)
+{
+ uint32_t index;
+
+ for (index = 1; index < len; index++)
+ {
+ temp_buff[(index * 2) - 1] = reg_addr[index];
+ temp_buff[index * 2] = reg_data[index];
+ }
+}
+
+/*!
+ * @brief This API is used to read the calibration parameters used
+ * for calculating the compensated data.
+ */
+static int8_t get_calib_param(struct bmp2_dev *dev)
+{
+ int8_t rslt;
+ uint8_t temp[BMP2_CALIB_DATA_SIZE] = { 0 };
+
+ rslt = bmp2_get_regs(BMP2_REG_DIG_T1_LSB, temp, BMP2_CALIB_DATA_SIZE, dev);
+
+ if (rslt == BMP2_OK)
+ {
+ dev->calib_param.dig_t1 = (uint16_t) (BMP2_MSBLSB_TO_U16(temp[BMP2_DIG_T1_MSB_POS], temp[BMP2_DIG_T1_LSB_POS]));
+ dev->calib_param.dig_t2 = (int16_t) (BMP2_MSBLSB_TO_U16(temp[BMP2_DIG_T2_MSB_POS], temp[BMP2_DIG_T2_LSB_POS]));
+ dev->calib_param.dig_t3 = (int16_t) (BMP2_MSBLSB_TO_U16(temp[BMP2_DIG_T3_MSB_POS], temp[BMP2_DIG_T3_LSB_POS]));
+ dev->calib_param.dig_p1 = (uint16_t) (BMP2_MSBLSB_TO_U16(temp[BMP2_DIG_P1_MSB_POS], temp[BMP2_DIG_P1_LSB_POS]));
+ dev->calib_param.dig_p2 = (int16_t) (BMP2_MSBLSB_TO_U16(temp[BMP2_DIG_P2_MSB_POS], temp[BMP2_DIG_P2_LSB_POS]));
+ dev->calib_param.dig_p3 = (int16_t) (BMP2_MSBLSB_TO_U16(temp[BMP2_DIG_P3_MSB_POS], temp[BMP2_DIG_P3_LSB_POS]));
+ dev->calib_param.dig_p4 = (int16_t) (BMP2_MSBLSB_TO_U16(temp[BMP2_DIG_P4_MSB_POS], temp[BMP2_DIG_P4_LSB_POS]));
+ dev->calib_param.dig_p5 = (int16_t) (BMP2_MSBLSB_TO_U16(temp[BMP2_DIG_P5_MSB_POS], temp[BMP2_DIG_P5_LSB_POS]));
+ dev->calib_param.dig_p6 = (int16_t) (BMP2_MSBLSB_TO_U16(temp[BMP2_DIG_P6_MSB_POS], temp[BMP2_DIG_P6_LSB_POS]));
+ dev->calib_param.dig_p7 = (int16_t) (BMP2_MSBLSB_TO_U16(temp[BMP2_DIG_P7_MSB_POS], temp[BMP2_DIG_P7_LSB_POS]));
+ dev->calib_param.dig_p8 = (int16_t) (BMP2_MSBLSB_TO_U16(temp[BMP2_DIG_P8_MSB_POS], temp[BMP2_DIG_P8_LSB_POS]));
+ dev->calib_param.dig_p9 = (int16_t) (BMP2_MSBLSB_TO_U16(temp[BMP2_DIG_P9_MSB_POS], temp[BMP2_DIG_P9_LSB_POS]));
+ dev->calib_param.dig_p10 = (int8_t) ((uint8_t)(temp[BMP2_DIG_P10_POS]));
+ }
+
+ return rslt;
+}
+
+/*!
+ * @brief This internal API to reset the sensor, restore/set conf, restore/set mode
+ */
+static int8_t conf_sensor(uint8_t mode, const struct bmp2_config *conf, struct bmp2_dev *dev)
+{
+ int8_t rslt;
+ uint8_t temp[2] = { 0, 0 };
+ uint8_t reg_addr[2] = { BMP2_REG_CTRL_MEAS, BMP2_REG_CONFIG };
+
+ if (conf != NULL)
+ {
+ rslt = bmp2_get_regs(BMP2_REG_CTRL_MEAS, temp, 2, dev);
+
+ if (rslt == BMP2_OK)
+ {
+ /* Here the intention is to put the device to sleep
+ * within the shortest period of time
+ */
+ rslt = bmp2_soft_reset(dev);
+
+ if (rslt == BMP2_OK)
+ {
+ set_os_mode(temp, conf);
+ temp[1] = BMP2_SET_BITS(temp[1], BMP2_STANDBY_DURN, conf->odr);
+ temp[1] = BMP2_SET_BITS(temp[1], BMP2_FILTER, conf->filter);
+ temp[1] = BMP2_SET_BITS_POS_0(temp[1], BMP2_SPI3_ENABLE, conf->spi3w_en);
+
+ rslt = bmp2_set_regs(reg_addr, temp, 2, dev);
+
+ if ((rslt == BMP2_OK) && (mode != BMP2_POWERMODE_SLEEP))
+ {
+ dev->power_mode = mode;
+
+ /* Write only the power mode register in a separate write */
+ temp[0] = BMP2_SET_BITS_POS_0(temp[0], BMP2_POWERMODE, mode);
+ rslt = bmp2_set_regs(reg_addr, temp, 1, dev);
+ }
+ }
+ }
+ }
+ else
+ {
+ rslt = BMP2_E_NULL_PTR;
+ }
+
+ return rslt;
+}
+
+/*!
+ * @brief This internal API is used to set the over-sampling rate of temperature and pressure
+ * based on the over-sampling mode.
+ */
+static void set_os_mode(uint8_t *reg_data, const struct bmp2_config *conf)
+{
+ switch (conf->os_mode)
+ {
+ case BMP2_OS_MODE_ULTRA_LOW_POWER:
+ reg_data[0] = BMP2_SET_BITS(reg_data[0], BMP2_OS_TEMP, BMP2_OS_1X);
+ reg_data[0] = BMP2_SET_BITS(reg_data[0], BMP2_OS_PRES, BMP2_OS_1X);
+ break;
+ case BMP2_OS_MODE_LOW_POWER:
+ reg_data[0] = BMP2_SET_BITS(reg_data[0], BMP2_OS_TEMP, BMP2_OS_1X);
+ reg_data[0] = BMP2_SET_BITS(reg_data[0], BMP2_OS_PRES, BMP2_OS_2X);
+ break;
+ case BMP2_OS_MODE_STANDARD_RESOLUTION:
+ reg_data[0] = BMP2_SET_BITS(reg_data[0], BMP2_OS_TEMP, BMP2_OS_1X);
+ reg_data[0] = BMP2_SET_BITS(reg_data[0], BMP2_OS_PRES, BMP2_OS_4X);
+ break;
+ case BMP2_OS_MODE_HIGH_RESOLUTION:
+ reg_data[0] = BMP2_SET_BITS(reg_data[0], BMP2_OS_TEMP, BMP2_OS_1X);
+ reg_data[0] = BMP2_SET_BITS(reg_data[0], BMP2_OS_PRES, BMP2_OS_8X);
+ break;
+ case BMP2_OS_MODE_ULTRA_HIGH_RESOLUTION:
+ reg_data[0] = BMP2_SET_BITS(reg_data[0], BMP2_OS_TEMP, BMP2_OS_2X);
+ reg_data[0] = BMP2_SET_BITS(reg_data[0], BMP2_OS_PRES, BMP2_OS_16X);
+ break;
+ default:
+ break;
+ }
+}
+
+/*!
+ * @brief This internal API is used to parse the pressure and temperature
+ * data and store it in the bmp2_uncomp_data structure instance.
+ */
+static int8_t parse_sensor_data(const uint8_t *reg_data, struct bmp2_uncomp_data *uncomp_data)
+{
+ int8_t rslt;
+
+ /* Variables to store the sensor data */
+ uint32_t data_xlsb;
+ uint32_t data_lsb;
+ uint32_t data_msb;
+
+ /* Store the parsed register values for pressure data */
+ data_msb = (uint32_t)reg_data[0] << 12;
+ data_lsb = (uint32_t)reg_data[1] << 4;
+ data_xlsb = (uint32_t)reg_data[2] >> 4;
+ uncomp_data->pressure = data_msb | data_lsb | data_xlsb;
+
+ /* Store the parsed register values for temperature data */
+ data_msb = (int32_t)reg_data[3] << 12;
+ data_lsb = (int32_t)reg_data[4] << 4;
+ data_xlsb = (int32_t)reg_data[5] >> 4;
+ uncomp_data->temperature = (int32_t)(data_msb | data_lsb | data_xlsb);
+
+ rslt = st_check_boundaries((int32_t)uncomp_data->temperature, (int32_t)uncomp_data->pressure);
+
+ return rslt;
+}
+
+#ifdef BMP2_DOUBLE_COMPENSATION
+
+/*!
+ * @brief This internal API is used to get the compensated temperature from
+ * uncompensated temperature. This API uses double floating precision.
+ */
+static int8_t compensate_temperature(double *comp_temperature,
+ const struct bmp2_uncomp_data *uncomp_data,
+ struct bmp2_dev *dev)
+{
+ int8_t rslt = BMP2_OK;
+ double var1, var2;
+ double temperature;
+
+ var1 = (((double) uncomp_data->temperature) / 16384.0 - ((double) dev->calib_param.dig_t1) / 1024.0) *
+ ((double) dev->calib_param.dig_t2);
+ var2 =
+ ((((double) uncomp_data->temperature) / 131072.0 - ((double) dev->calib_param.dig_t1) / 8192.0) *
+ (((double) uncomp_data->temperature) / 131072.0 - ((double) dev->calib_param.dig_t1) / 8192.0)) *
+ ((double) dev->calib_param.dig_t3);
+
+ dev->calib_param.t_fine = (int32_t) (var1 + var2);
+ temperature = (var1 + var2) / 5120.0;
+
+ if (temperature < BMP2_MIN_TEMP_DOUBLE)
+ {
+ temperature = BMP2_MIN_TEMP_DOUBLE;
+ rslt = BMP2_W_MIN_TEMP;
+ }
+
+ if (temperature > BMP2_MAX_TEMP_DOUBLE)
+ {
+ temperature = BMP2_MAX_TEMP_DOUBLE;
+ rslt = BMP2_W_MAX_TEMP;
+ }
+
+ (*comp_temperature) = temperature;
+
+ return rslt;
+}
+
+/*!
+ * @brief This internal API is used to get the compensated pressure from
+ * uncompensated pressure. This API uses double floating precision.
+ */
+static int8_t compensate_pressure(double *comp_pressure,
+ const struct bmp2_uncomp_data *uncomp_data,
+ const struct bmp2_dev *dev)
+{
+ int8_t rslt = BMP2_OK;
+ double var1, var2;
+ double pressure = 0.0;
+
+ var1 = ((double) dev->calib_param.t_fine / 2.0) - 64000.0;
+ var2 = var1 * var1 * ((double) dev->calib_param.dig_p6) / 32768.0;
+ var2 = var2 + var1 * ((double) dev->calib_param.dig_p5) * 2.0;
+ var2 = (var2 / 4.0) + (((double) dev->calib_param.dig_p4) * 65536.0);
+ var1 = (((double)dev->calib_param.dig_p3) * var1 * var1 / 524288.0 + ((double)dev->calib_param.dig_p2) * var1) /
+ 524288.0;
+ var1 = (1.0 + var1 / 32768.0) * ((double) dev->calib_param.dig_p1);
+
+ if (var1 < 0 || var1 > 0)
+ {
+ pressure = 1048576.0 - (double)uncomp_data->pressure;
+ pressure = (pressure - (var2 / 4096.0)) * 6250.0 / var1;
+ var1 = ((double)dev->calib_param.dig_p9) * pressure * pressure / 2147483648.0;
+ var2 = pressure * ((double)dev->calib_param.dig_p8) / 32768.0;
+
+ pressure = pressure + (var1 + var2 + ((double)dev->calib_param.dig_p7)) / 16.0;
+
+ if (pressure < BMP2_MIN_PRES_DOUBLE)
+ {
+ pressure = BMP2_MIN_PRES_DOUBLE;
+ rslt = BMP2_W_MIN_PRES;
+ }
+
+ if (pressure > BMP2_MAX_PRES_DOUBLE)
+ {
+ pressure = BMP2_MAX_PRES_DOUBLE;
+ rslt = BMP2_W_MAX_PRES;
+ }
+
+ (*comp_pressure) = pressure;
+ }
+
+ return rslt;
+}
+
+#else
+
+/*!
+ * @brief This internal API is used to get the compensated temperature from
+ * uncompensated temperature. This API uses 32bit integer data type.
+ */
+static int8_t compensate_temperature(int32_t *comp_temperature,
+ const struct bmp2_uncomp_data *uncomp_data,
+ struct bmp2_dev *dev)
+{
+ int8_t rslt = BMP2_OK;
+ int32_t var1, var2;
+ int32_t temperature;
+
+ var1 =
+ ((((uncomp_data->temperature / 8) - ((int32_t) dev->calib_param.dig_t1 * 2))) *
+ ((int32_t) dev->calib_param.dig_t2)) / 2048;
+ var2 =
+ (((((uncomp_data->temperature / 16) - ((int32_t) dev->calib_param.dig_t1)) *
+ ((uncomp_data->temperature / 16) - ((int32_t) dev->calib_param.dig_t1))) / 4096) *
+ ((int32_t) dev->calib_param.dig_t3)) / 16384;
+
+ dev->calib_param.t_fine = var1 + var2;
+
+ temperature = (dev->calib_param.t_fine * 5 + 128) / 256;
+
+ if (temperature < BMP2_MIN_TEMP_INT)
+ {
+ temperature = BMP2_MIN_TEMP_INT;
+ rslt = BMP2_W_MIN_TEMP;
+ }
+
+ if (temperature > BMP2_MAX_TEMP_INT)
+ {
+ temperature = BMP2_MAX_TEMP_INT;
+ rslt = BMP2_W_MAX_TEMP;
+ }
+
+ (*comp_temperature) = temperature;
+
+ return rslt;
+}
+
+#ifndef BMP2_32BIT_COMPENSATION
+
+/*!
+ * @brief This internal API is used to get the compensated pressure from
+ * uncompensated pressure. This API uses 64bit integer data type.
+ */
+static int8_t compensate_pressure(uint32_t *comp_pressure,
+ const struct bmp2_uncomp_data *uncomp_data,
+ const struct bmp2_dev *dev)
+{
+ int8_t rslt = BMP2_OK;
+ int64_t var1, var2, p;
+ uint32_t pressure = 0;
+
+ var1 = ((int64_t) dev->calib_param.t_fine) - 128000;
+ var2 = var1 * var1 * (int64_t) dev->calib_param.dig_p6;
+ var2 = var2 + ((var1 * (int64_t) dev->calib_param.dig_p5) * 131072);
+ var2 = var2 + (((int64_t) dev->calib_param.dig_p4) * 34359738368);
+ var1 = ((var1 * var1 * (int64_t) dev->calib_param.dig_p3) / 256) +
+ ((var1 * (int64_t) dev->calib_param.dig_p2) * 4096);
+ var1 = (((((int64_t)1) * 140737488355328) + var1)) * ((int64_t)dev->calib_param.dig_p1) / 8589934592;
+
+ if (var1 != 0)
+ {
+ p = 1048576 - uncomp_data->pressure;
+ p = (((p * 2147483648) - var2) * 3125) / var1;
+ var1 = (((int64_t) dev->calib_param.dig_p9) * (p / 8192) * (p / 8192)) / 33554432;
+ var2 = (((int64_t) dev->calib_param.dig_p8) * p) / 524288;
+
+ p = ((p + var1 + var2) / 256) + (((int64_t)dev->calib_param.dig_p7) * 16);
+ pressure = (uint32_t)p;
+
+ if (pressure < BMP2_MIN_PRES_64INT)
+ {
+ pressure = BMP2_MIN_PRES_64INT;
+ rslt = BMP2_W_MIN_PRES;
+ }
+
+ if (pressure > BMP2_MAX_PRES_64INT)
+ {
+ pressure = BMP2_MAX_PRES_64INT;
+ rslt = BMP2_W_MAX_PRES;
+ }
+
+ (*comp_pressure) = pressure;
+ }
+
+ return rslt;
+}
+
+#else
+
+/*!
+ * @brief This internal API is used to get the compensated pressure from
+ * uncompensated pressure. This API uses 32bit integer data type.
+ */
+static int8_t compensate_pressure(uint32_t *comp_pressure,
+ const struct bmp2_uncomp_data *uncomp_data,
+ const struct bmp2_dev *dev)
+{
+ int8_t rslt = BMP2_OK;
+ int32_t var1, var2;
+ uint32_t pressure = 0;
+
+ var1 = (((int32_t) dev->calib_param.t_fine) / 2) - (int32_t) 64000;
+ var2 = (((var1 / 4) * (var1 / 4)) / 2048) * ((int32_t) dev->calib_param.dig_p6);
+ var2 = var2 + ((var1 * ((int32_t) dev->calib_param.dig_p5)) * 2);
+ var2 = (var2 / 4) + (((int32_t) dev->calib_param.dig_p4) * 65536);
+ var1 =
+ (((dev->calib_param.dig_p3 * (((var1 / 4) * (var1 / 4)) / 8192)) / 8) +
+ ((((int32_t) dev->calib_param.dig_p2) * var1) / 2)) / 262144;
+ var1 = ((((32768 + var1)) * ((int32_t) dev->calib_param.dig_p1)) / 32768);
+
+ /* Avoid exception caused by division with zero */
+ if (var1 != 0)
+ {
+ pressure = (((uint32_t)(((int32_t)1048576) - uncomp_data->pressure) - (var2 / 4096))) * 3125;
+
+ /* Check for overflows against UINT32_MAX/2; if pressure is left-shifted by 1 */
+ if (pressure < 0x80000000)
+ {
+ pressure = (pressure * 2) / ((uint32_t) var1);
+ }
+ else
+ {
+ pressure = (pressure / (uint32_t) var1) * 2;
+ }
+
+ var1 = (((int32_t) dev->calib_param.dig_p9) * ((int32_t) (((pressure / 8) * (pressure / 8)) / 8192))) / 4096;
+ var2 = (((int32_t) (pressure / 4)) * ((int32_t) dev->calib_param.dig_p8)) / 8192;
+ pressure = (uint32_t) ((int32_t) pressure + ((var1 + var2 + dev->calib_param.dig_p7) / 16));
+
+ if (pressure < BMP2_MIN_PRES_32INT)
+ {
+ pressure = BMP2_MIN_PRES_32INT;
+ rslt = BMP2_W_MIN_PRES;
+ }
+
+ if (pressure > BMP2_MAX_PRES_32INT)
+ {
+ pressure = BMP2_MAX_PRES_32INT;
+ rslt = BMP2_W_MAX_PRES;
+ }
+
+ (*comp_pressure) = pressure;
+ }
+
+ return rslt;
+}
+
+#endif
+#endif
+
+/*!
+ * @This internal API checks whether the uncompensated temperature and
+ * uncompensated pressure are within the range
+ */
+static int8_t st_check_boundaries(int32_t utemperature, int32_t upressure)
+{
+ int8_t rslt = 0;
+
+ /* Check Uncompensated pressure in not valid range AND uncompensated temperature in valid range */
+ if ((upressure < BMP2_ST_ADC_P_MIN || upressure > BMP2_ST_ADC_P_MAX) &&
+ (utemperature >= BMP2_ST_ADC_T_MIN && utemperature <= BMP2_ST_ADC_T_MAX))
+ {
+ rslt = BMP2_E_UNCOMP_PRESS_RANGE;
+ }
+ /* Check Uncompensated temperature in not valid range AND uncompensated pressure in valid range */
+ else if ((utemperature < BMP2_ST_ADC_T_MIN || utemperature > BMP2_ST_ADC_T_MAX) &&
+ (upressure >= BMP2_ST_ADC_P_MIN && upressure <= BMP2_ST_ADC_P_MAX))
+ {
+ rslt = BMP2_E_UNCOMP_TEMP_RANGE;
+ }
+ /* Check Uncompensated pressure in not valid range AND uncompensated temperature in not valid range */
+ else if ((upressure < BMP2_ST_ADC_P_MIN || upressure > BMP2_ST_ADC_P_MAX) &&
+ (utemperature < BMP2_ST_ADC_T_MIN || utemperature > BMP2_ST_ADC_T_MAX))
+ {
+ rslt = BMP2_E_UNCOMP_TEMP_AND_PRESS_RANGE;
+ }
+ else
+ {
+ rslt = BMP2_OK;
+ }
+
+ return rslt;
+}
diff --git a/main/drivers/drv_bmp280_3v3/bmp2/bmp2.h b/main/drivers/drv_bmp280_3v3/bmp2/bmp2.h
new file mode 100644
index 0000000..c5ba31a
--- /dev/null
+++ b/main/drivers/drv_bmp280_3v3/bmp2/bmp2.h
@@ -0,0 +1,393 @@
+/**
+* Copyright (c) 2021 Bosch Sensortec GmbH. All rights reserved.
+*
+* BSD-3-Clause
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+*
+* 1. Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+*
+* 2. Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution.
+*
+* 3. Neither the name of the copyright holder nor the names of its
+* contributors may be used to endorse or promote products derived from
+* this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+* POSSIBILITY OF SUCH DAMAGE.
+*
+* @file bmp2.h
+* @date 2021-05-21
+* @version v1.0.1
+*
+*/
+
+/*! @file bmp2.h
+ * @brief Sensor driver for BMP2 sensor
+ */
+
+/*!
+ * @defgroup bmp2 BMP2
+ */
+
+#ifndef _BMP2_H
+#define _BMP2_H
+
+/*! CPP guard */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/****************************************************************************/
+
+/*! Header files
+ ****************************************************************************/
+#include "bmp2_defs.h"
+
+/***************************************************************************/
+
+/*! BMP2 User Interface function prototypes
+ ****************************************************************************/
+
+/**
+ * \ingroup bmp2
+ * \defgroup bmp2ApiInit Initialization
+ * @brief Perform initialization of sensor
+ */
+
+/*!
+ * \ingroup bmp2ApiInit
+ * \page bmp2_api_bmp2_init bmp2_init
+ * \code
+ * int8_t bmp2_init(struct bmp2_dev *dev);
+ * \endcode
+ * @details This API is the entry point.
+ * It reads the chip-id and calibration data from the sensor.
+ *
+ * @param[in,out] dev : Structure instance of bmp2_dev
+ *
+ * @return Result of API execution status.
+ *
+ * @retval 0 -> Success.
+ * @retval < 0 -> Fail.
+ */
+int8_t bmp2_init(struct bmp2_dev *dev);
+
+/**
+ * \ingroup bmp2
+ * \defgroup bmp2ApiRegs Registers
+ * @brief Initialize the sensor and device structure
+ */
+
+/*!
+ * \ingroup bmp2ApiRegs
+ * \page bmp2_api_bmp2_get_regs bmp2_get_regs
+ * \code
+ * int8_t bmp2_get_regs(uint8_t reg_addr, uint8_t *reg_data, uint32_t len, struct bmp2_dev *dev);
+ * \endcode
+ * @details This API reads the data from the given register address of the
+ * sensor.
+ *
+ * @param[in] reg_addr : Register address from where the data to be read
+ * @param[out] reg_data : Pointer to data buffer to store the read data.
+ * @param[in] len : No of bytes of data to be read.
+ * @param[in] dev : Structure instance of bmp2_dev.
+ *
+ * @return Result of API execution status.
+ *
+ * @retval 0 -> Success.
+ * @retval < 0 -> Fail.
+ */
+int8_t bmp2_get_regs(uint8_t reg_addr, uint8_t *reg_data, uint32_t len, struct bmp2_dev *dev);
+
+/*!
+ * \ingroup bmp2ApiRegs
+ * \page bmp2_api_bmp2_set_regs bmp2_set_regs
+ * \code
+ * int8_t bmp2_set_regs(uint8_t *reg_addr, const uint8_t *reg_data, uint32_t len, struct bmp2_dev *dev);
+ * \endcode
+ * @details This API writes the given data to the register addresses
+ * of the sensor.
+ *
+ * @param[in] reg_addr : Register address from where the data to be written.
+ * @param[in] reg_data : Pointer to data buffer which is to be written
+ * in the sensor.
+ * @param[in] len : No of bytes of data to write..
+ * @param[in] dev : Structure instance of bmp2_dev.
+ *
+ * @return Result of API execution status.
+ *
+ * @retval 0 -> Success.
+ * @retval < 0 -> Fail.
+ */
+int8_t bmp2_set_regs(uint8_t *reg_addr, const uint8_t *reg_data, uint32_t len, struct bmp2_dev *dev);
+
+/**
+ * \ingroup bmp2
+ * \defgroup bmp2ApiSoftreset Soft reset
+ * @brief Perform self test
+ */
+
+/*!
+ * \ingroup bmp2ApiSoftreset
+ * \page bmp2_api_bmp2_soft_reset bmp2_soft_reset
+ * \code
+ * int8_t bmp2_soft_reset(struct bmp2_dev *dev);
+ * \endcode
+ * @details This API triggers the soft reset of the sensor.
+ *
+ * @param[in] dev : Structure instance of bmp2_dev.
+ *
+ * @return Result of API execution status.
+ *
+ * @retval 0 -> Success.
+ * @retval < 0 -> Fail.
+ */
+int8_t bmp2_soft_reset(struct bmp2_dev *dev);
+
+/**
+ * \ingroup bmp2
+ * \defgroup bmp2ApiPowermode Power mode
+ * @brief Set / Get power mode of the sensor
+ */
+
+/*!
+ * \ingroup bmp2ApiPowermode
+ * \page bmp2_api_bmp2_get_power_mode bmp2_get_power_mode
+ * \code
+ * int8_t bmp2_get_power_mode(uint8_t *mode, struct bmp2_dev *dev);
+ * \endcode
+ * @details This API reads the power mode.
+ *
+ * @param[out] mode : BMP2_POWERMODE_SLEEP, BMP2_POWERMODE_NORMAL,
+ * BMP2_POWERMODE_FORCED
+ * @param[in] dev : Structure instance of bmp2_dev
+ *
+ * @return Result of API execution status.
+ *
+ * @retval 0 -> Success.
+ * @retval < 0 -> Fail.
+ */
+int8_t bmp2_get_power_mode(uint8_t *mode, struct bmp2_dev *dev);
+
+/*!
+ * \ingroup bmp2ApiPowermode
+ * \page bmp2_api_bmp2_set_power_mode bmp2_set_power_mode
+ * \code
+ * int8_t bmp2_set_power_mode(uint8_t mode, const struct bmp2_config *conf, struct bmp2_dev *dev);
+ * \endcode
+ * @details This API writes the power mode.
+ *
+ * @param[in] mode : BMP2_POWERMODE_SLEEP, BMP2_POWERMODE_NORMAL,
+ * BMP2_POWERMODE_FORCED
+ * @param[in] conf : Structure instance of bmp2_config
+ * @param[in] dev : Structure instance of bmp2_dev
+ *
+ * @return Result of API execution status.
+ *
+ * @retval 0 -> Success.
+ * @retval < 0 -> Fail.
+ */
+int8_t bmp2_set_power_mode(uint8_t mode, const struct bmp2_config *conf, struct bmp2_dev *dev);
+
+/**
+ * \ingroup bmp2
+ * \defgroup bmp2ApiConfig Configuration
+ * @brief Set / Get configurations of the sensor
+ */
+
+/*!
+ * \ingroup bmp2ApiConfig
+ * \page bmp2_api_bmp2_get_config bmp2_get_config
+ * \code
+ * int8_t bmp2_get_config(struct bmp2_config *conf, struct bmp2_dev *dev);
+ * \endcode
+ * @details This API reads the data from the ctrl_meas register and config
+ * register. It gives the currently set temperature and pressure over-sampling
+ * configuration, power mode configuration, sleep duration and
+ * IIR filter coefficient.
+ *
+ * @param[out] conf : Current configuration of the bmp2
+ * conf->osrs_t, conf->osrs_p = BMP2_OS_NONE, BMP2_OS_1X,
+ * BMP2_OS_2X, BMP2_OS_4X, BMP2_OS_8X, BMP2_OS_16X
+ *
+ * conf->odr = BMP2_ODR_0_5_MS, BMP2_ODR_62_5_MS, BMP2_ODR_125_MS,
+ * BMP2_ODR_250_MS, BMP2_ODR_500_MS, BMP2_ODR_1000_MS,
+ * BMP2_ODR_2000_MS, BMP2_ODR_4000_MS
+ *
+ * conf->filter = BMP2_FILTER_OFF, BMP2_FILTER_COEFF_2,
+ * BMP2_FILTER_COEFF_4, BMP2_FILTER_COEFF_8, BMP2_FILTER_COEFF_16
+ *
+ * conf->spi3w_en = BMP2_SPI3_WIRE_ENABLE, BMP2_SPI3_WIRE_DISABLE
+ *
+ * @param[in] dev : Structure instance of bmp2_dev
+ *
+ * @return Result of API execution status.
+ *
+ * @retval 0 -> Success.
+ * @retval < 0 -> Fail.
+ */
+int8_t bmp2_get_config(struct bmp2_config *conf, struct bmp2_dev *dev);
+
+/*!
+ * \ingroup bmp2ApiConfig
+ * \page bmp2_api_bmp2_set_config bmp2_set_config
+ * \code
+ * int8_t bmp2_set_config(const struct bmp2_config *conf, struct bmp2_dev *dev);
+ * \endcode
+ * @details This API writes the data to the ctrl_meas register and config register.
+ * It sets the over-sampling mode, power mode configuration,
+ * sleep duration and IIR filter coefficient.
+ *
+ * @param[in] conf : Desired configuration to the bmp2
+ * conf->osrs_t, conf->osrs_p = BMP2_OS_NONE, BMP2_OS_1X,
+ * BMP2_OS_2X, BMP2_OS_4X, BMP2_OS_8X, BMP2_OS_16X
+ *
+ * conf->odr = BMP2_ODR_0_5_MS, BMP2_ODR_62_5_MS, BMP2_ODR_125_MS,
+ * BMP2_ODR_250_MS, BMP2_ODR_500_MS, BMP2_ODR_1000_MS,
+ * BMP2_ODR_2000_MS, BMP2_ODR_4000_MS
+ *
+ * conf->filter = BMP2_FILTER_OFF, BMP2_FILTER_COEFF_2,
+ * BMP2_FILTER_COEFF_4, BMP2_FILTER_COEFF_8, BMP2_FILTER_COEFF_16
+ *
+ * conf->spi3w_en = BMP2_SPI3_WIRE_ENABLE, BMP2_SPI3_WIRE_DISABLE
+ *
+ * Over-sampling settings | conf->os_pres | conf->os_temp
+ *--------------------------|-------------------|---------------------------
+ * Ultra low power | 1 | 1
+ * Low power | 2 | 1
+ * Standard resolution | 4 | 1
+ * High resolution | 8 | 1
+ * Ultra high resolution | 16 | 2
+ *
+ * @param[in] dev : Structure instance of bmp2_dev
+ *
+ * @return Result of API execution status.
+ *
+ * @retval 0 -> Success.
+ * @retval < 0 -> Fail.
+ */
+int8_t bmp2_set_config(const struct bmp2_config *conf, struct bmp2_dev *dev);
+
+/**
+ * \ingroup bmp2
+ * \defgroup bmp2ApiStatus Status register
+ * @brief Read status register
+ */
+
+/*!
+ * \ingroup bmp2ApiStatus
+ * \page bmp2_api_bmp2_get_status bmp2_get_status
+ * \code
+ * int8_t bmp2_get_status(struct bmp2_status *status, struct bmp2_dev *dev);
+ * \endcode
+ * @details This API reads the status register
+ *
+ * @param[in,out] status : Structure instance of bmp2_status.
+ * @param[in] dev : Structure instance of bmp2_dev
+ *
+ * @return Result of API execution status.
+ *
+ * @retval 0 -> Success.
+ * @retval < 0 -> Fail.
+ */
+int8_t bmp2_get_status(struct bmp2_status *status, struct bmp2_dev *dev);
+
+/**
+ * \ingroup bmp2
+ * \defgroup bmp2ApiSensorData Sensor Data
+ * @brief Data processing of sensor
+ */
+
+/*!
+ * \ingroup bmp2ApiSensorData
+ * \page bmp2_api_bmp2_get_sensor_data bmp2_get_sensor_data
+ * \code
+ * int8_t bmp2_get_sensor_data(struct bmp2_data *comp_data, struct bmp2_dev *dev);
+ * \endcode
+ * @details This API reads the pressure and temperature data from the
+ * sensor, compensates the data and store it in the bmp2_data structure
+ * instance passed by the user.
+ *
+ * @param[in] comp_data : Structure instance of bmp2_data
+ * @param[in] dev : Structure instance of bmp2_dev
+ *
+ * @return Result of API execution status.
+ *
+ * @retval 0 -> Success.
+ * @retval < 0 -> Fail.
+ */
+int8_t bmp2_get_sensor_data(struct bmp2_data *comp_data, struct bmp2_dev *dev);
+
+/*!
+ * \ingroup bmp2ApiSensorData
+ * \page bmp2_api_bmp2_compensate_data bmp2_compensate_data
+ * \code
+ * int8_t bmp2_compensate_data(const struct bmp2_uncomp_data *uncomp_data,
+ * struct bmp2_data *comp_data,
+ * struct bmp2_dev *dev);
+ * \endcode
+ * @details This API is used to compensate the pressure and
+ * temperature data.
+ *
+ * @param[in] uncomp_data : Contains the uncompensated pressure, temperature data.
+ * @param[out] comp_data : Contains the compensated pressure and/or temperature data.
+ * @param[in] dev : Structure instance of bmp2_dev.
+ *
+ * @return Result of API execution status.
+ *
+ * @retval 0 -> Success.
+ * @retval > 0 -> Warning.
+ * @retval < 0 -> Fail.
+ *
+ */
+int8_t bmp2_compensate_data(const struct bmp2_uncomp_data *uncomp_data,
+ struct bmp2_data *comp_data,
+ struct bmp2_dev *dev);
+
+/**
+ * \ingroup bmp2
+ * \defgroup bmp2ApiMeasTime Compute measurement time
+ * @brief Computes measurement time (in microseconds)
+ */
+
+/*!
+ * \ingroup bmp2ApiMeasTime
+ * \page bmp2_api_bmp2_compute_meas_time bmp2_compute_meas_time
+ * \code
+ * int8_t bmp2_compute_meas_time(uint32_t *sampling_time, const struct bmp2_config *conf, const struct bmp2_dev *dev);
+ * \endcode
+ * @details This API computes the measurement time in microseconds for the
+ * active configuration based on standbytime(conf->odr) and over-sampling mode(conf->os_mode)
+ *
+ * @param[out] sampling_time : Measurement time for the active configuration in microseconds
+ * @param[in] conf : Structure instance of bmp2_config
+ * @param[in] dev : Structure instance of bmp2_dev
+ *
+ * @return Result of API execution status.
+ *
+ * @retval 0 -> Success.
+ * @retval < 0 -> Fail.
+ *
+ */
+int8_t bmp2_compute_meas_time(uint32_t *sampling_time, const struct bmp2_config *conf, const struct bmp2_dev *dev);
+
+#ifdef __cplusplus
+}
+#endif /* End of CPP guard */
+
+#endif /* _BMP2_H */
diff --git a/main/drivers/drv_bmp280_3v3/bmp2/bmp2_defs.h b/main/drivers/drv_bmp280_3v3/bmp2/bmp2_defs.h
new file mode 100644
index 0000000..8ac811c
--- /dev/null
+++ b/main/drivers/drv_bmp280_3v3/bmp2/bmp2_defs.h
@@ -0,0 +1,602 @@
+/**
+* Copyright (c) 2021 Bosch Sensortec GmbH. All rights reserved.
+*
+* BSD-3-Clause
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+*
+* 1. Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+*
+* 2. Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution.
+*
+* 3. Neither the name of the copyright holder nor the names of its
+* contributors may be used to endorse or promote products derived from
+* this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+* POSSIBILITY OF SUCH DAMAGE.
+*
+* @file bmp2_defs.h
+* @date 2021-05-21
+* @version v1.0.1
+*
+*/
+
+/*! @file bmp2_defs.h
+ * @brief Sensor driver for BMP2 sensor
+ */
+
+#ifndef _BMP2_DEFS_H
+#define _BMP2_DEFS_H
+
+/*! CPP guard */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/****************************************************************/
+/*! @name Header includes */
+/****************************************************************/
+#ifdef __KERNEL__
+#include
+#include
+#else
+#include
+#include
+#endif
+
+/****************************************************************/
+/*! @name Common macros */
+/****************************************************************/
+#ifdef __KERNEL__
+#if !defined(UINT8_C) && !defined(INT8_C)
+#define INT8_C(x) S8_C(x)
+#define UINT8_C(x) U8_C(x)
+#endif
+
+#if !defined(UINT16_C) && !defined(INT16_C)
+#define INT16_C(x) S16_C(x)
+#define UINT16_C(x) U16_C(x)
+#endif
+
+#if !defined(INT32_C) && !defined(UINT32_C)
+#define INT32_C(x) S32_C(x)
+#define UINT32_C(x) U32_C(x)
+#endif
+
+#if !defined(INT64_C) && !defined(UINT64_C)
+#define INT64_C(x) S64_C(x)
+#define UINT64_C(x) U64_C(x)
+#endif
+#endif
+
+/*! @name C standard macros */
+#ifndef NULL
+#ifdef __cplusplus
+#define NULL 0
+#else
+#define NULL ((void *) 0)
+#endif
+#endif
+
+/******************************************************************************/
+/*! @name Compiler switch macros Definitions */
+/******************************************************************************/
+#ifndef BMP2_64BIT_COMPENSATION /*< Check if 64bit (using BMP2_64BIT_COMPENSATION) is enabled */
+#ifndef BMP2_32BIT_COMPENSATION /*< Check if 32bit (using BMP2_32BIT_COMPENSATION) is enabled */
+#ifndef BMP2_DOUBLE_COMPENSATION /*< If any of the integer data types not enabled then enable
+ * BMP2_DOUBLE_COMPENSATION */
+#define BMP2_DOUBLE_COMPENSATION
+#endif
+#endif
+#endif
+
+/******************************************************************************/
+/*! @name General Macro Definitions */
+/******************************************************************************/
+
+/*! @name Maximum write length to registers */
+#define BMP2_MAX_LEN UINT8_C(4)
+
+/*! @name Return codes */
+/*! @name Success code*/
+#define BMP2_OK INT8_C(0)
+
+/*! @name Error codes */
+#define BMP2_E_NULL_PTR INT8_C(-1)
+#define BMP2_E_COM_FAIL INT8_C(-2)
+#define BMP2_E_INVALID_LEN INT8_C(-3)
+#define BMP2_E_DEV_NOT_FOUND INT8_C(-4)
+#define BMP2_E_UNCOMP_TEMP_RANGE INT8_C(-5)
+#define BMP2_E_UNCOMP_PRESS_RANGE INT8_C(-6)
+#define BMP2_E_UNCOMP_TEMP_AND_PRESS_RANGE INT8_C(-7)
+
+/*! @name Warning codes */
+#define BMP2_W_MIN_TEMP INT8_C(1)
+#define BMP2_W_MAX_TEMP INT8_C(2)
+#define BMP2_W_MIN_PRES INT8_C(3)
+#define BMP2_W_MAX_PRES INT8_C(4)
+
+/*! @name Chip ID */
+#define BMP2_CHIP_ID UINT8_C(0x58)
+
+/*! @name I2C addresses */
+#define BMP2_I2C_ADDR_PRIM UINT8_C(0x76)
+#define BMP2_I2C_ADDR_SEC UINT8_C(0x77)
+
+/*! @name Register addresses */
+#define BMP2_REG_CHIP_ID UINT8_C(0xD0)
+#define BMP2_REG_SOFT_RESET UINT8_C(0xE0)
+#define BMP2_REG_STATUS UINT8_C(0xF3)
+#define BMP2_REG_CTRL_MEAS UINT8_C(0xF4)
+#define BMP2_REG_CONFIG UINT8_C(0xF5)
+#define BMP2_REG_PRES_MSB UINT8_C(0xF7)
+#define BMP2_REG_PRES_LSB UINT8_C(0xF8)
+#define BMP2_REG_PRES_XLSB UINT8_C(0xF9)
+#define BMP2_REG_TEMP_MSB UINT8_C(0xFA)
+#define BMP2_REG_TEMP_LSB UINT8_C(0xFB)
+#define BMP2_REG_TEMP_XLSB UINT8_C(0xFC)
+
+/* Calibration parameter register addresses */
+#define BMP2_REG_DIG_T1_LSB UINT8_C(0x88)
+#define BMP2_REG_DIG_T1_MSB UINT8_C(0x89)
+#define BMP2_REG_DIG_T2_LSB UINT8_C(0x8A)
+#define BMP2_REG_DIG_T2_MSB UINT8_C(0x8B)
+#define BMP2_REG_DIG_T3_LSB UINT8_C(0x8C)
+#define BMP2_REG_DIG_T3_MSB UINT8_C(0x8D)
+#define BMP2_REG_DIG_P1_LSB UINT8_C(0x8E)
+#define BMP2_REG_DIG_P1_MSB UINT8_C(0x8F)
+#define BMP2_REG_DIG_P2_LSB UINT8_C(0x90)
+#define BMP2_REG_DIG_P2_MSB UINT8_C(0x91)
+#define BMP2_REG_DIG_P3_LSB UINT8_C(0x92)
+#define BMP2_REG_DIG_P3_MSB UINT8_C(0x93)
+#define BMP2_REG_DIG_P4_LSB UINT8_C(0x94)
+#define BMP2_REG_DIG_P4_MSB UINT8_C(0x95)
+#define BMP2_REG_DIG_P5_LSB UINT8_C(0x96)
+#define BMP2_REG_DIG_P5_MSB UINT8_C(0x97)
+#define BMP2_REG_DIG_P6_LSB UINT8_C(0x98)
+#define BMP2_REG_DIG_P6_MSB UINT8_C(0x99)
+#define BMP2_REG_DIG_P7_LSB UINT8_C(0x9A)
+#define BMP2_REG_DIG_P7_MSB UINT8_C(0x9B)
+#define BMP2_REG_DIG_P8_LSB UINT8_C(0x9C)
+#define BMP2_REG_DIG_P8_MSB UINT8_C(0x9D)
+#define BMP2_REG_DIG_P9_LSB UINT8_C(0x9E)
+#define BMP2_REG_DIG_P9_MSB UINT8_C(0x9F)
+
+/*! @name Interface settings */
+#define BMP2_SPI_RD_MASK UINT8_C(0x80)
+#define BMP2_SPI_WR_MASK UINT8_C(0x7F)
+
+/*! @name Delay definition */
+#define BMP2_DELAY_US_STARTUP_TIME UINT8_C(2000)
+
+/*! @name Power modes */
+#define BMP2_POWERMODE_SLEEP UINT8_C(0x00)
+#define BMP2_POWERMODE_FORCED UINT8_C(0x01)
+#define BMP2_POWERMODE_NORMAL UINT8_C(0x03)
+
+#define BMP2_POWERMODE_POS UINT8_C(0x00)
+#define BMP2_POWERMODE_MSK UINT8_C(0x03)
+
+/*! @name Soft reset command */
+#define BMP2_SOFT_RESET_CMD UINT8_C(0xB6)
+
+/*! @name Data length */
+#define BMP2_P_T_LEN UINT8_C(0X06)
+
+/*! @name Temperature range values in integer(32bit, 64bit) and float */
+#define BMP2_MIN_TEMP_INT INT32_C(-4000)
+#define BMP2_MAX_TEMP_INT INT32_C(8500)
+#define BMP2_MIN_TEMP_DOUBLE -40.0f
+#define BMP2_MAX_TEMP_DOUBLE 85.0f
+
+/*! @name Pressure range values in integer and float */
+#define BMP2_MIN_PRES_32INT UINT32_C(30000)
+#define BMP2_MAX_PRES_32INT UINT32_C(110000)
+#define BMP2_MIN_PRES_64INT UINT32_C(30000 * 256)
+#define BMP2_MAX_PRES_64INT UINT32_C(110000 * 256)
+#define BMP2_MIN_PRES_DOUBLE 30000.0f
+#define BMP2_MAX_PRES_DOUBLE 110000.0f
+
+/*! @name ODR options */
+#define BMP2_ODR_0_5_MS UINT8_C(0x00)
+#define BMP2_ODR_62_5_MS UINT8_C(0x01)
+#define BMP2_ODR_125_MS UINT8_C(0x02)
+#define BMP2_ODR_250_MS UINT8_C(0x03)
+#define BMP2_ODR_500_MS UINT8_C(0x04)
+#define BMP2_ODR_1000_MS UINT8_C(0x05)
+#define BMP2_ODR_2000_MS UINT8_C(0x06)
+#define BMP2_ODR_4000_MS UINT8_C(0x07)
+
+/*! @name Over-sampling macros */
+#define BMP2_OS_NONE UINT8_C(0x00)
+#define BMP2_OS_1X UINT8_C(0x01)
+#define BMP2_OS_2X UINT8_C(0x02)
+#define BMP2_OS_4X UINT8_C(0x03)
+#define BMP2_OS_8X UINT8_C(0x04)
+#define BMP2_OS_16X UINT8_C(0x05)
+#define BMP2_OS_TEMP_POS UINT8_C(0x05)
+#define BMP2_OS_TEMP_MSK UINT8_C(0xE0)
+#define BMP2_OS_PRES_POS UINT8_C(0x02)
+#define BMP2_OS_PRES_MSK UINT8_C(0x1C)
+
+/*! @name Over-sampling mode */
+#define BMP2_OS_MODE_ULTRA_LOW_POWER UINT8_C(0x00)
+#define BMP2_OS_MODE_LOW_POWER UINT8_C(0x01)
+#define BMP2_OS_MODE_STANDARD_RESOLUTION UINT8_C(0x02)
+#define BMP2_OS_MODE_HIGH_RESOLUTION UINT8_C(0x03)
+#define BMP2_OS_MODE_ULTRA_HIGH_RESOLUTION UINT8_C(0x04)
+
+/*! @name Filter coefficient macros */
+#define BMP2_FILTER_OFF UINT8_C(0x00)
+#define BMP2_FILTER_COEFF_2 UINT8_C(0x01)
+#define BMP2_FILTER_COEFF_4 UINT8_C(0x02)
+#define BMP2_FILTER_COEFF_8 UINT8_C(0x03)
+#define BMP2_FILTER_COEFF_16 UINT8_C(0x04)
+
+#define BMP2_FILTER_POS UINT8_C(0x02)
+#define BMP2_FILTER_MSK UINT8_C(0x1C)
+
+/*! @name SPI 3-Wire macros */
+#define BMP2_SPI3_WIRE_ENABLE UINT8_C(0x01)
+#define BMP2_SPI3_WIRE_DISABLE UINT8_C(0x00)
+
+#define BMP2_SPI3_ENABLE_POS UINT8_C(0x00)
+#define BMP2_SPI3_ENABLE_MSK UINT8_C(0x01)
+
+/*! @name Measurement status macros */
+#define BMP2_MEAS_DONE UINT8_C(0x00)
+#define BMP2_MEAS_ONGOING UINT8_C(0x01)
+
+#define BMP2_STATUS_MEAS_POS UINT8_C(0x03)
+#define BMP2_STATUS_MEAS_MSK UINT8_C(0x08)
+
+/*! @name Image update status macros */
+#define BMP2_IM_UPDATE_DONE UINT8_C(0x00)
+#define BMP2_IM_UPDATE_ONGOING UINT8_C(0x01)
+
+#define BMP2_STATUS_IM_UPDATE_POS UINT8_C(0x00)
+#define BMP2_STATUS_IM_UPDATE_MSK UINT8_C(0x01)
+
+/*! @name Standby duration macros */
+#define BMP2_STANDBY_DURN_POS UINT8_C(0x05)
+#define BMP2_STANDBY_DURN_MSK UINT8_C(0xE0)
+
+/*! @name Calibration parameters' relative position */
+#define BMP2_DIG_T1_LSB_POS UINT8_C(0)
+#define BMP2_DIG_T1_MSB_POS UINT8_C(1)
+#define BMP2_DIG_T2_LSB_POS UINT8_C(2)
+#define BMP2_DIG_T2_MSB_POS UINT8_C(3)
+#define BMP2_DIG_T3_LSB_POS UINT8_C(4)
+#define BMP2_DIG_T3_MSB_POS UINT8_C(5)
+#define BMP2_DIG_P1_LSB_POS UINT8_C(6)
+#define BMP2_DIG_P1_MSB_POS UINT8_C(7)
+#define BMP2_DIG_P2_LSB_POS UINT8_C(8)
+#define BMP2_DIG_P2_MSB_POS UINT8_C(9)
+#define BMP2_DIG_P3_LSB_POS UINT8_C(10)
+#define BMP2_DIG_P3_MSB_POS UINT8_C(11)
+#define BMP2_DIG_P4_LSB_POS UINT8_C(12)
+#define BMP2_DIG_P4_MSB_POS UINT8_C(13)
+#define BMP2_DIG_P5_LSB_POS UINT8_C(14)
+#define BMP2_DIG_P5_MSB_POS UINT8_C(15)
+#define BMP2_DIG_P6_LSB_POS UINT8_C(16)
+#define BMP2_DIG_P6_MSB_POS UINT8_C(17)
+#define BMP2_DIG_P7_LSB_POS UINT8_C(18)
+#define BMP2_DIG_P7_MSB_POS UINT8_C(19)
+#define BMP2_DIG_P8_LSB_POS UINT8_C(20)
+#define BMP2_DIG_P8_MSB_POS UINT8_C(21)
+#define BMP2_DIG_P9_LSB_POS UINT8_C(22)
+#define BMP2_DIG_P9_MSB_POS UINT8_C(23)
+#define BMP2_DIG_P10_POS UINT8_C(24)
+#define BMP2_CALIB_DATA_SIZE UINT8_C(25)
+
+/*! @brief Macros holding the minimum and maximum for trimming values */
+#define BMP2_ST_DIG_T1_MIN UINT16_C(19000)
+#define BMP2_ST_DIG_T1_MAX UINT16_C(35000)
+#define BMP2_ST_DIG_T2_MIN UINT16_C(22000)
+#define BMP2_ST_DIG_T2_MAX UINT16_C(30000)
+#define BMP2_ST_DIG_T3_MIN INT16_C(-3000)
+#define BMP2_ST_DIG_T3_MAX INT16_C(-1000)
+#define BMP2_ST_DIG_P1_MIN UINT16_C(30000)
+#define BMP2_ST_DIG_P1_MAX UINT16_C(42000)
+#define BMP2_ST_DIG_P2_MIN INT16_C(-12970)
+#define BMP2_ST_DIG_P2_MAX INT16_C(-8000)
+#define BMP2_ST_DIG_P3_MIN INT16_C(-5000)
+#define BMP2_ST_DIG_P3_MAX UINT16_C(8000)
+#define BMP2_ST_DIG_P4_MIN INT16_C(-10000)
+#define BMP2_ST_DIG_P4_MAX UINT16_C(18000)
+#define BMP2_ST_DIG_P5_MIN INT16_C(-500)
+#define BMP2_ST_DIG_P5_MAX UINT16_C(1100)
+#define BMP2_ST_DIG_P6_MIN INT16_C(-1000)
+#define BMP2_ST_DIG_P6_MAX UINT16_C(1000)
+#define BMP2_ST_DIG_P7_MIN INT16_C(-32768)
+#define BMP2_ST_DIG_P7_MAX UINT16_C(32767)
+#define BMP2_ST_DIG_P8_MIN INT16_C(-30000)
+#define BMP2_ST_DIG_P8_MAX UINT16_C(10000)
+#define BMP2_ST_DIG_P9_MIN INT16_C(-10000)
+#define BMP2_ST_DIG_P9_MAX UINT16_C(30000)
+
+/*! @brief Macros holding the minimum and maximum for trimming values */
+/* 0x00000 is minimum output value */
+#define BMP2_ST_ADC_T_MIN INT32_C(0x00000)
+
+/* 0xFFFF0 is maximum 20-bit output value without over sampling */
+#define BMP2_ST_ADC_T_MAX INT32_C(0xFFFF0)
+
+/* 0x00000 is minimum output value */
+#define BMP2_ST_ADC_P_MIN INT32_C(0x00000)
+
+/* 0xFFFF0 is maximum 20-bit output value without over sampling */
+#define BMP2_ST_ADC_P_MAX INT32_C(0xFFFF0)
+
+/*! @brief Macros to read out API revision number */
+/* Register holding custom trimming values */
+#define BMP2_ST_TRIMCUSTOM_REG UINT8_C(0x87)
+#define BMP2_ST_TRIMCUSTOM_REG_APIREV_POS UINT8_C(1)
+#define BMP2_ST_TRIMCUSTOM_REG_APIREV_MSK UINT8_C(0x06)
+#define BMP2_ST_TRIMCUSTOM_REG_APIREV_LEN UINT8_C(2)
+#define BMP2_ST_TRIMCUSTOM_REG_APIREV_REG BMP2_ST_TRIMCUSTOM_REG
+
+/* Highest API revision supported is revision 0. */
+#define BMP2_ST_MAX_APIREVISION UINT8_C(0x00)
+
+#define BMP2_MSBLSB_TO_U16(msb, lsb) (((uint16_t)msb << 8) | ((uint16_t)lsb))
+
+/*! @name Bit-slicing macros */
+#define BMP2_GET_BITS(reg_data, bitname) ((reg_data & bitname##_MSK) \
+ >> bitname##_POS)
+#define BMP2_SET_BITS(reg_data, bitname, val) ((reg_data & \
+ ~bitname##_MSK) | ((val << bitname##_POS) & bitname##_MSK))
+#define BMP2_SET_BITS_POS_0(reg_data, bitname, data) ((reg_data & \
+ ~(bitname##_MSK)) | (data & bitname##_MSK))
+#define BMP2_GET_BITS_POS_0(reg_data, bitname) (reg_data & \
+ (bitname##_MSK))
+
+/******************************************************************************/
+/*! @name Function Pointers */
+/******************************************************************************/
+#ifndef BMP2_INTF_RET_TYPE
+#define BMP2_INTF_RET_TYPE int8_t
+#endif
+
+#ifndef BMP2_INTF_RET_SUCCESS
+#define BMP2_INTF_RET_SUCCESS INT8_C(0)
+#endif
+
+/*!
+ * @brief Bus communication function pointer which should be mapped to
+ * the platform specific read functions of the user
+ *
+ * @param[in] reg_addr : 8bit register address of the sensor
+ * @param[out] reg_data : Data from the specified address
+ * @param[in] length : Length of the reg_data array
+ * @param[in,out] intf_ptr : Void pointer that can enable the linking of descriptors
+ * for interface related callbacks
+ * @retval 0 for Success
+ * @retval Non-zero for Failure
+ */
+typedef BMP2_INTF_RET_TYPE (*bmp2_read_fptr_t)(uint8_t reg_addr, uint8_t *reg_data, uint32_t length, void *intf_ptr);
+
+/*!
+ * @brief Bus communication function pointer which should be mapped to
+ * the platform specific read functions of the user
+ *
+ * @param[in] reg_addr : 8bit register address of the sensor
+ * @param[out] reg_data : Data from the specified address
+ * @param[in] length : Length of the reg_data array
+ * @param[in,out] intf_ptr : Void pointer that can enable the linking of descriptors
+ * for interface related callbacks
+ * @retval 0 for Success
+ * @retval Non-zero for Failure
+ */
+typedef BMP2_INTF_RET_TYPE (*bmp2_write_fptr_t)(uint8_t reg_addr, const uint8_t *reg_data, uint32_t length,
+ void *intf_ptr);
+
+/*!
+ * @brief Delay function pointer which should be mapped to
+ * delay function of the user
+ *
+ * @param period - The time period in microseconds
+ * @param[in,out] intf_ptr : Void pointer that can enable the linking of descriptors
+ * for interface related callbacks
+ */
+typedef void (*bmp2_delay_us_fptr_t)(uint32_t period, void *intf_ptr);
+
+/******************************************************************************/
+/*! @name Enum Declarations */
+/******************************************************************************/
+
+/*!
+ * @brief Enum to define BMP2 sensor interfaces
+ */
+enum bmp2_intf {
+ /*! SPI interface */
+ BMP2_SPI_INTF,
+ /*! I2C interface */
+ BMP2_I2C_INTF
+};
+
+/******************************************************************************/
+/*! @name Structure Declarations */
+/******************************************************************************/
+
+/*!
+ * @brief Calibration parameters' structure
+ */
+struct bmp2_calib_param
+{
+ /*! Calibration parameter of temperature data */
+
+ /*! Calibration t1 data */
+ uint16_t dig_t1;
+
+ /*! Calibration t2 data */
+ int16_t dig_t2;
+
+ /*! Calibration t3 data */
+ int16_t dig_t3;
+
+ /*! Calibration parameter of pressure data */
+
+ /*! Calibration p1 data */
+ uint16_t dig_p1;
+
+ /*! Calibration p2 data */
+ int16_t dig_p2;
+
+ /*! Calibration p3 data */
+ int16_t dig_p3;
+
+ /*! Calibration p4 data */
+ int16_t dig_p4;
+
+ /*! Calibration p5 data */
+ int16_t dig_p5;
+
+ /*! Calibration p6 data */
+ int16_t dig_p6;
+
+ /*! Calibration p7 data */
+ int16_t dig_p7;
+
+ /*! Calibration p8 data */
+ int16_t dig_p8;
+
+ /*! Calibration p9 data */
+ int16_t dig_p9;
+
+ /*! Calibration p10 data */
+ int8_t dig_p10;
+
+ /*! Fine resolution temperature value */
+ int32_t t_fine;
+};
+
+/*!
+ * @brief Sensor configuration structure
+ */
+struct bmp2_config
+{
+ /*! Over-sampling of temperature data */
+ uint8_t os_temp;
+
+ /*! Over-sampling of pressure data */
+ uint8_t os_pres;
+
+ /*! Odr set by setting standby duration */
+ uint8_t odr;
+
+ /*! Over-sampling mode */
+ uint8_t os_mode;
+
+ /*! Time constant of IIR filter */
+ uint8_t filter;
+
+ /*! Enable 3-wire SPI interface */
+ uint8_t spi3w_en;
+};
+
+/*!
+ * @brief Sensor status structure
+ */
+struct bmp2_status
+{
+ /*! Data registers' status */
+ uint8_t measuring;
+
+ /*! Image register status */
+ uint8_t im_update;
+};
+
+/*!
+ * @brief Uncompensated data structure
+ */
+struct bmp2_uncomp_data
+{
+ /*! Uncompensated temperature data */
+ int32_t temperature;
+
+ /*! Uncompensated pressure data */
+ uint32_t pressure;
+};
+
+/*!
+ * @brief bmp2 sensor structure which comprises of temperature and pressure
+ */
+#ifdef BMP2_DOUBLE_COMPENSATION
+struct bmp2_data
+{
+ /*! Compensated pressure */
+ double pressure;
+
+ /*! Compensated temperature */
+ double temperature;
+};
+#else
+struct bmp2_data
+{
+ /*! Compensated pressure */
+ uint32_t pressure;
+
+ /*! Compensated temperature */
+ int32_t temperature;
+};
+#endif
+
+/*!
+ * @brief API device structure
+ */
+struct bmp2_dev
+{
+ /*! Chip Id */
+ uint8_t chip_id;
+
+ /*! SPI/I2C Interface selection */
+ enum bmp2_intf intf;
+
+ /*!
+ * The interface pointer is used to enable the user
+ * to link their interface descriptors for reference during the
+ * implementation of the read and write interfaces to the
+ * hardware.
+ */
+ void *intf_ptr;
+
+ /*! Variable that holds result of read/write function */
+ BMP2_INTF_RET_TYPE intf_rslt;
+
+ /*! Bus read function pointer */
+ bmp2_read_fptr_t read;
+
+ /*! Bus write function pointer */
+ bmp2_write_fptr_t write;
+
+ /*! Delay(in us) function pointer */
+ bmp2_delay_us_fptr_t delay_us;
+
+ /*! Powermode of the sensor */
+ uint8_t power_mode;
+
+ /*! Structure of calibration parameters' */
+ struct bmp2_calib_param calib_param;
+};
+
+#ifdef __cplusplus
+}
+#endif /* End of CPP guard */
+
+#endif /* _BMP2_DEFS_H */
diff --git a/main/drivers/drv_bmp280_3v3/drv_bmp280_3v3.c b/main/drivers/drv_bmp280_3v3/drv_bmp280_3v3.c
new file mode 100644
index 0000000..12e69f3
--- /dev/null
+++ b/main/drivers/drv_bmp280_3v3/drv_bmp280_3v3.c
@@ -0,0 +1,170 @@
+/**
+ * @file drv_bmp280_3v3.c
+ * @author impressionyang (impressionyang@outlook.com)
+ * @brief
+ * @version 0.1
+ * @date 2022-10-09
+ * _ _
+ * (_)_ _ ___ _______ ___ ___ (_)__ ___ __ _____ ____ ___ _
+ * / / ' \/ _ \/ __/ -_|_-<(_- / _ \/ _ \/ // / _ `/ _ \/ _ `/
+ * /_/_/_/_/ .__/_/ \__/___/___/_/\___/_//_/\_, /\_,_/_//_/\_, /
+ * /_/ /___/ /___/
+ * @copyright Copyright (c) 2022 impressionyang
+ *
+ * @par 修改日志:
+ *
+ * | Date | Version | Author | Description
+ * |
|---|
| 2022-10-09 | v1.0 | impressionyang | 内容
+ * |
+ */
+#include "drv_bmp280_3v3.h"
+#include
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+
+static struct bmp2_status status = {0};
+static struct bmp2_data comp_data = {0};
+static struct bmp2_dev dev = {0};
+static struct bmp2_config conf = {0};
+static uint8_t dev_addr = BMP2_I2C_ADDR_PRIM;
+
+static void bmp2_error_codes_print_result(const char api_name[], int8_t rslt)
+{
+ if (rslt != BMP2_OK)
+ {
+ printf("%s\t", api_name);
+
+ switch (rslt)
+ {
+ case BMP2_E_NULL_PTR:
+ printf("Error [%d] : Null pointer error.", rslt);
+ printf(
+ "It occurs when the user tries to assign value (not address) to a pointer, which has been initialized to NULL.\r\n");
+ break;
+ case BMP2_E_COM_FAIL:
+ printf("Error [%d] : Communication failure error.", rslt);
+ printf(
+ "It occurs due to read/write operation failure and also due to power failure during communication\r\n");
+ break;
+ case BMP2_E_INVALID_LEN:
+ printf("Error [%d] : Invalid length error.", rslt);
+ printf("Occurs when length of data to be written is zero\n");
+ break;
+ case BMP2_E_DEV_NOT_FOUND:
+ printf("Error [%d] : Device not found error. It occurs when the device chip id is incorrectly read\r\n",
+ rslt);
+ break;
+ case BMP2_E_UNCOMP_TEMP_RANGE:
+ printf("Error [%d] : Uncompensated temperature data not in valid range error.", rslt);
+ break;
+ case BMP2_E_UNCOMP_PRESS_RANGE:
+ printf("Error [%d] : Uncompensated pressure data not in valid range error.", rslt);
+ break;
+ case BMP2_E_UNCOMP_TEMP_AND_PRESS_RANGE:
+ printf(
+ "Error [%d] : Uncompensated pressure data and uncompensated temperature data are not in valid range error.",
+ rslt);
+ break;
+ default:
+ printf("Error [%d] : Unknown error code\r\n", rslt);
+ break;
+ }
+ }
+}
+
+uint8_t drv_bmp280_3v3_init(drv_bmp280_3v3_t *handle)
+{
+ if (!handle || !handle->drv_i2c_read || !handle->drv_i2c_write) {
+ return 1;
+ }
+
+ int8_t rslt;
+ uint32_t meas_time;
+
+ dev.read = handle->drv_i2c_read;
+ dev.write = handle->drv_i2c_write;
+ dev.delay_us = handle->delay_10ms;
+ dev.intf = BMP2_I2C_INTF;
+ dev.intf_ptr = &dev_addr;
+
+ handle->chip_addr = BMP2_I2C_ADDR_PRIM;
+ handle->is_drv_init = 1;
+ handle->drv_state = 1;
+ printf("1 addr of handle dev = %08x\r\n", (unsigned int)handle->dev);
+
+ handle->dev = &dev;
+
+ printf("2 addr of handle dev = %08x\r\n", (unsigned int)handle->dev);
+
+ rslt = bmp2_init(handle->dev);
+ bmp2_error_codes_print_result("bmp2_init", rslt);
+
+ rslt = bmp2_get_config(&conf, handle->dev);
+ bmp2_error_codes_print_result("bmp2_get_config", rslt);
+
+ conf.filter = BMP2_FILTER_OFF;
+ conf.os_mode = BMP2_OS_MODE_HIGH_RESOLUTION;
+ conf.odr = BMP2_ODR_250_MS;
+
+ rslt = bmp2_set_config(&conf, handle->dev);
+ bmp2_error_codes_print_result("bmp2_set_config", rslt);
+
+ rslt = bmp2_set_power_mode(BMP2_POWERMODE_NORMAL, &conf, handle->dev);
+ bmp2_error_codes_print_result("bmp2_set_power_mode", rslt);
+ rslt = bmp2_compute_meas_time(&meas_time, &conf, handle->dev);
+ bmp2_error_codes_print_result("bmp2_compute_meas_time", rslt);
+
+ drv_bmp280_3v3_refresh_data(handle);
+
+ return 0;
+}
+
+uint8_t drv_bmp280_3v3_refresh_data(drv_bmp280_3v3_t *handle)
+{
+ if (!handle) {
+ return 1;
+ }
+
+ int8_t rslt = BMP2_E_NULL_PTR;
+
+ rslt = bmp2_get_status(&status, handle->dev);
+ bmp2_error_codes_print_result("bmp2_get_status", rslt);
+
+ if (status.measuring == BMP2_MEAS_DONE)
+ {
+ rslt = bmp2_get_sensor_data(&comp_data, handle->dev);
+ bmp2_error_codes_print_result("bmp2_get_sensor_data", rslt);
+
+ }else {
+ return 1;
+ }
+
+ return 0;
+}
+
+uint8_t drv_bmp280_3v3_get_pressure(drv_bmp280_3v3_t *handle, double *presure)
+{
+ if (!handle) {
+ return 1;
+ }
+
+ *presure = comp_data.pressure;
+
+ return 0;
+}
+
+uint8_t drv_bmp280_3v3_get_tempreture(drv_bmp280_3v3_t *handle, double *temperature)
+{
+ if (!handle) {
+ return 1;
+ }
+
+ *temperature = comp_data.temperature;
+ return 0;
+}
+
+uint8_t drv_bmp280_3v3_deinit(drv_bmp280_3v3_t *handle)
+{
+ handle->is_drv_init = 0;
+ return 0;
+}
diff --git a/main/drivers/drv_bmp280_3v3/drv_bmp280_3v3.h b/main/drivers/drv_bmp280_3v3/drv_bmp280_3v3.h
new file mode 100644
index 0000000..ea4d62b
--- /dev/null
+++ b/main/drivers/drv_bmp280_3v3/drv_bmp280_3v3.h
@@ -0,0 +1,51 @@
+/**
+ * @file drv_bmp280_3v3.h
+ * @author impressionyang (impressionyang@outlook.com)
+ * @brief
+ * @version 0.1
+ * @date 2022-10-09
+ * _ _
+ * (_)_ _ ___ _______ ___ ___ (_)__ ___ __ _____ ____ ___ _
+ * / / ' \/ _ \/ __/ -_|_-<(_- / _ \/ _ \/ // / _ `/ _ \/ _ `/
+ * /_/_/_/_/ .__/_/ \__/___/___/_/\___/_//_/\_, /\_,_/_//_/\_, /
+ * /_/ /___/ /___/
+ * @copyright Copyright (c) 2022 impressionyang
+ *
+ * @par 修改日志:
+ *
+ * | Date | Version | Author | Description
+ * |
|---|
| 2022-10-09 | v1.0 | impressionyang | 内容
+ * |
+ */
+#ifndef __DRV_BMP280_3V3_H__
+#define __DRV_BMP280_3V3_H__
+
+#include
+#include "bmp2.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef struct _drv_bmp280_3v3_t_
+{
+ uint8_t is_drv_init;
+ uint8_t drv_state;
+ uint8_t chip_addr;
+ int8_t (*drv_i2c_read)(uint8_t reg_addr, uint8_t *data, uint32_t data_len, void *chip_addr);
+ int8_t (*drv_i2c_write)(uint8_t reg_addr, const uint8_t *data, uint32_t data_len, void *chip_addr);
+ uint8_t (*delay_10ms)(uint32_t period, void *intf_ptr);
+ struct bmp2_dev *dev;
+} drv_bmp280_3v3_t;
+
+uint8_t drv_bmp280_3v3_init(drv_bmp280_3v3_t *handle);
+uint8_t drv_bmp280_3v3_refresh_data(drv_bmp280_3v3_t *handle);
+uint8_t drv_bmp280_3v3_get_pressure(drv_bmp280_3v3_t *handle, double *presure);
+uint8_t drv_bmp280_3v3_get_tempreture(drv_bmp280_3v3_t *handle, double *temperature);
+uint8_t drv_bmp280_3v3_deinit(drv_bmp280_3v3_t *handle);
+
+#ifdef __cplusplus
+}
+#endif
+#endif//__DRV_BMP280_3V3_H__
\ No newline at end of file
diff --git a/main/drivers/msg_queue/msg_queue.c b/main/drivers/msg_queue/msg_queue.c
new file mode 100644
index 0000000..f4b4577
--- /dev/null
+++ b/main/drivers/msg_queue/msg_queue.c
@@ -0,0 +1,211 @@
+/**
+ * @file msg_queue.c
+ * @author impressionyang (impressionyang@outlook.com)
+ * @brief
+ * @version 0.1
+ * @date 2022-10-09
+ * _ _
+ * (_)_ _ ___ _______ ___ ___ (_)__ ___ __ _____ ____ ___ _
+ * / / ' \/ _ \/ __/ -_|_-<(_- / _ \/ _ \/ // / _ `/ _ \/ _ `/
+ * /_/_/_/_/ .__/_/ \__/___/___/_/\___/_//_/\_, /\_,_/_//_/\_, /
+ * /_/ /___/ /___/
+ * @copyright Copyright (c) 2022 impressionyang
+ *
+ * @par 修改日志:
+ *
+ * | Date | Version | Author | Description
+ * |
|---|
| 2022-10-09 | v1.0 | impressionyang | 内容
+ * |
+ */
+#include "msg_queue.h"
+#include "link_list.h"
+#include
+#include
+
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/queue.h"
+
+typedef struct _msg_queue_list_node_t_
+{
+ char *msg_queue_name;
+ QueueHandle_t xQueue_handle;
+} msg_queue_list_node_t;
+
+link_list_handle_t *sg_msg_list = NULL;
+
+/**
+ *
+ * @brief 检查是否存在
+ * @author impressionyang (impressionyang@outlook.com)
+ * @param [in] msg_queue_name
+ * @return uint8_t 0:存在 | 非0:不存在
+ *
+ * @details
+ */
+static uint8_t _msg_queue_check_msg_q_is_exist(char *msg_queue_name)
+{
+ uint8_t result = 1;
+ link_list_node_t *node = sg_msg_list->link_list_header;
+ msg_queue_list_node_t *msg_node = NULL;
+
+ if (NULL == msg_queue_name) {
+ // pointer is null
+ return 2;
+ }
+
+ if (NULL == node) {
+ return 3;
+ }
+
+ for (; node->next != NULL; node = node->next) {
+ msg_node = node->node_data_ptr;
+ if (strcmp(msg_queue_name, msg_node->msg_queue_name) == 0) {
+ result = 0;
+ break;
+ }
+ }
+ return result;
+}
+
+static uint8_t _msg_queue_get_msg_q_node(char *msg_queue_name, msg_queue_list_node_t *node_need, uint16_t *node_id)
+{
+ uint8_t result = 1;
+ link_list_node_t *node = sg_msg_list->link_list_header;
+ msg_queue_list_node_t *msg_node = NULL;
+
+ if (NULL == msg_queue_name) {
+ // pointer is null
+ return 2;
+ }
+
+ printf("_msg_queue_get_msg_q_node %s\r\n", msg_queue_name);
+
+ if (node != NULL && node->next == NULL) {
+ msg_node = node->node_data_ptr;
+ printf("%s : %s\r\n", msg_queue_name, msg_node->msg_queue_name);
+ if (strcmp(msg_queue_name, msg_node->msg_queue_name) == 0) {
+ result = 0;
+ memcpy(node_need, msg_node, sizeof(msg_queue_list_node_t));
+ return 0;
+ }
+ }
+
+ for (; node != NULL && node->next != NULL; node = node->next) {
+ msg_node = node->node_data_ptr;
+ printf("%s : %s\r\n", msg_queue_name, msg_node->msg_queue_name);
+ if (strcmp(msg_queue_name, msg_node->msg_queue_name) == 0) {
+ result = 0;
+ memcpy(node_need, msg_node, sizeof(msg_queue_list_node_t));
+ break;
+ }
+ }
+ return result;
+}
+
+uint8_t msg_queue_init()
+{
+ sg_msg_list = link_list_init();
+ return 0;
+}
+
+uint8_t msg_queue_create(char *msg_queue_name)
+{
+ printf("msg_queue_create: line %d\r\n", __LINE__);
+ uint8_t ret = 0, msg_node_id;
+
+ if (NULL == msg_queue_name) {
+ return 1;
+ }
+ printf("msg_queue_create: line %d\r\n", __LINE__);
+
+ ret = _msg_queue_check_msg_q_is_exist(msg_queue_name);
+ if (!ret) {
+ return 2;
+ }
+ printf("msg_queue_create: line %d\r\n", __LINE__);
+
+ msg_queue_list_node_t *msg_node = malloc(sizeof(msg_queue_list_node_t));
+ printf("msg_queue_create: line %d\r\n", __LINE__);
+ msg_node->msg_queue_name = msg_queue_name;
+ msg_node->xQueue_handle = xQueueCreate(20, sizeof(msg_data_t));
+ printf("msg_queue_create: line %d\r\n", __LINE__);
+ link_list_append_node_to_tail(sg_msg_list, msg_node, &msg_node_id);
+ printf("msg_queue_create: line %d\r\n", __LINE__);
+
+ return 0;
+}
+
+uint8_t msg_queue_send_msg(char *receiver, msg_data_t *msg)
+{
+ uint8_t ret = 0;
+ uint16_t node_id = 0;
+ msg_queue_list_node_t msg_node = {0};
+ ret = _msg_queue_get_msg_q_node(receiver, &msg_node, &node_id);
+ printf("msg_queue_send_msg _msg_queue_get_msg_q_node ret = %d\r\n", ret);
+ if (ret) {
+ return 1;
+ }
+
+ if(xQueueSend(msg_node.xQueue_handle, (void *)msg, (TickType_t)10) != pdPASS)
+ {
+ // Failed to post the message, even after 10 ticks.
+ return 2;
+ }
+
+ return 0;
+}
+
+uint8_t msg_queue_recive_msg(char *msg_queue_name, msg_data_t *msg_data_ptr, uint16_t timeout)
+{
+ uint8_t ret = 0;
+ uint16_t node_id = 0;
+ msg_queue_list_node_t msg_node = {0};
+ msg_data_t *msg_data_ptr_in_queue = NULL;
+ ret = _msg_queue_get_msg_q_node(msg_queue_name, &msg_node, &node_id);
+ printf("msg_queue_recive_msg _msg_queue_get_msg_q_node ret = %d\r\n", ret);
+
+ if (ret) {
+ return 1;
+ }
+
+ if (xQueueReceive(msg_node.xQueue_handle, &msg_data_ptr_in_queue, (TickType_t)timeout))
+ {
+ // msg_data_ptr now points to the struct AMessage variable posted
+ // by vATask.
+ memcpy(msg_data_ptr, msg_data_ptr_in_queue, sizeof(msg_data_t));
+ return 0;
+ }
+ return 1;
+}
+
+uint8_t msg_queue_destroy(char *msg_queue_name)
+{
+ uint8_t ret = 0;
+ uint16_t node_id = 0;
+ msg_queue_list_node_t msg_node = {0};
+ ret = _msg_queue_get_msg_q_node(msg_queue_name, &msg_node, &node_id);
+
+ if (ret) {
+ return 1;
+ }
+
+ vQueueDelete(msg_node.xQueue_handle);
+ link_list_delete_node_by_id(sg_msg_list, node_id);
+
+ return 0;
+}
+
+uint8_t msg_queue_deinit()
+{
+ link_list_node_t *node = sg_msg_list->link_list_header;
+ msg_queue_list_node_t *msg_node = NULL;
+
+ for (; node->next != NULL;) {
+ msg_node = node->node_data_ptr;
+ node = node->next;
+ msg_queue_destroy(msg_node->msg_queue_name);
+ }
+ return 0;
+}
+
diff --git a/main/drivers/msg_queue/msg_queue.h b/main/drivers/msg_queue/msg_queue.h
new file mode 100644
index 0000000..45f5c4f
--- /dev/null
+++ b/main/drivers/msg_queue/msg_queue.h
@@ -0,0 +1,112 @@
+/**
+ * @file msg_queue.h
+ * @author impressionyang (impressionyang@outlook.com)
+ * @brief 消息队列的驱动,用来进行动态创建、获取、删除消息队列句柄的
+ * @version 0.1
+ * @date 2022-10-09
+ * _ _
+ * (_)_ _ ___ _______ ___ ___ (_)__ ___ __ _____ ____ ___ _
+ * / / ' \/ _ \/ __/ -_|_-<(_- / _ \/ _ \/ // / _ `/ _ \/ _ `/
+ * /_/_/_/_/ .__/_/ \__/___/___/_/\___/_//_/\_, /\_,_/_//_/\_, /
+ * /_/ /___/ /___/
+ * @copyright Copyright (c) 2022 impressionyang
+ *
+ * @par 修改日志:
+ *
+ * | Date | Version | Author | Description
+ * |
|---|
| 2022-10-09 | v1.0 | impressionyang | 内容
+ * |
+ */
+#ifndef __MSG_QUEUE_H__
+#define __MSG_QUEUE_H__
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _msg_data_t_
+{
+ uint16_t msg_id;
+ uint16_t msg_reserve;
+ uint16_t msg_type;
+ uint16_t msg_value;
+ union
+ {
+ uint32_t msg_data;
+ void* msg_ptr;
+ };
+} msg_data_t;
+
+/**
+ *
+ * @brief 初始化消息队列链表
+ * @author impressionyang (impressionyang@outlook.com)
+ * @return uint8_t
+ *
+ * @details
+ */
+uint8_t msg_queue_init();
+
+/**
+ *
+ * @brief 创建一个消息队列
+ * @author impressionyang (impressionyang@outlook.com)
+ * @param [in] msg_queue_name
+ * @return uint8_t
+ *
+ * @details
+ */
+uint8_t msg_queue_create(char *msg_queue_name);
+
+/**
+ *
+ * @brief 给指定的消息队列发送消息
+ * @author impressionyang (impressionyang@outlook.com)
+ * @param [in] receiver
+ * @param [in] msg
+ * @return uint8_t
+ *
+ * @details
+ */
+uint8_t msg_queue_send_msg(char *receiver, msg_data_t *msg);
+
+/**
+ *
+ * @brief 从消息队列收取消息
+ * @author impressionyang (impressionyang@outlook.com)
+ * @param [in] msg_queue_name
+ * @param [in] msg_data_ptr
+ * @param [in] timeout
+ * @return uint8_t
+ *
+ * @details
+ */
+uint8_t msg_queue_recive_msg(char *msg_queue_name, msg_data_t *msg_data_ptr, uint16_t timeout);
+
+/**
+ *
+ * @brief 销毁一个存在的消息队列
+ * @author impressionyang (impressionyang@outlook.com)
+ * @param [in] msg_queue_name
+ * @return uint8_t
+ *
+ * @details
+ */
+uint8_t msg_queue_destroy(char *msg_queue_name);
+
+/**
+ *
+ * @brief 去初始化消息队列
+ * @author impressionyang (impressionyang@outlook.com)
+ * @return uint8_t
+ *
+ * @details
+ */
+uint8_t msg_queue_deinit();
+
+#ifdef __cplusplus
+}
+#endif
+#endif//__MSG_QUEUE_H__
\ No newline at end of file
diff --git a/main/drivers/st7789/bmpfile.h b/main/drivers/st7789/bmpfile.h
new file mode 100644
index 0000000..95f70e3
--- /dev/null
+++ b/main/drivers/st7789/bmpfile.h
@@ -0,0 +1,51 @@
+#ifndef __bmpfile_h__
+#define __bmpfile_h__
+
+typedef struct {
+ uint8_t magic[2]; /* the magic number used to identify the BMP file:
+ 0x42 0x4D (Hex code points for B and M).
+ The following entries are possible:
+ BM - Windows 3.1x, 95, NT, ... etc
+ BA - OS/2 Bitmap Array
+ CI - OS/2 Color Icon
+ CP - OS/2 Color Pointer
+ IC - OS/2 Icon
+ PT - OS/2 Pointer. */
+ uint32_t filesz; /* the size of the BMP file in bytes */
+ uint16_t creator1; /* reserved. */
+ uint16_t creator2; /* reserved. */
+ uint32_t offset; /* the offset, i.e. starting address,
+ of the byte where the bitmap data can be found. */
+} bmp_header_t;
+
+typedef struct {
+ uint32_t header_sz; /* the size of this header (40 bytes) */
+ uint32_t width; /* the bitmap width in pixels */
+ uint32_t height; /* the bitmap height in pixels */
+ uint16_t nplanes; /* the number of color planes being used.
+ Must be set to 1. */
+ uint16_t depth; /* the number of bits per pixel,
+ which is the color depth of the image.
+ Typical values are 1, 4, 8, 16, 24 and 32. */
+ uint32_t compress_type; /* the compression method being used.
+ See also bmp_compression_method_t. */
+ uint32_t bmp_bytesz; /* the image size. This is the size of the raw bitmap
+ data (see below), and should not be confused
+ with the file size. */
+ uint32_t hres; /* the horizontal resolution of the image.
+ (pixel per meter) */
+ uint32_t vres; /* the vertical resolution of the image.
+ (pixel per meter) */
+ uint32_t ncolors; /* the number of colors in the color palette,
+ or 0 to default to 2n. */
+ uint32_t nimpcolors; /* the number of important colors used,
+ or 0 when every color is important;
+ generally ignored. */
+} bmp_dib_v3_header_t;
+
+typedef struct {
+ bmp_header_t header;
+ bmp_dib_v3_header_t dib;
+} bmpfile_t;
+
+#endif /* __bmpfile_h__ */
diff --git a/main/drivers/st7789/decode_jpeg.c b/main/drivers/st7789/decode_jpeg.c
new file mode 100644
index 0000000..06fdae7
--- /dev/null
+++ b/main/drivers/st7789/decode_jpeg.c
@@ -0,0 +1,186 @@
+#include
+#include "decode_jpeg.h"
+#include "esp32/rom/tjpgd.h"
+#include "esp_log.h"
+
+//Data that is passed from the decoder function to the infunc/outfunc functions.
+typedef struct {
+ pixel_jpeg **outData; // Array of IMAGE_H pointers to arrays of 16-bit pixel values
+ int screenWidth; // Width of the screen
+ int screenHeight; // Height of the screen
+ FILE* fp; // File pointer of jpeg file
+} JpegDev;
+
+
+//Input function for jpeg decoder. Just returns bytes from the inData field of the JpegDev structure.
+static UINT infunc(JDEC *decoder, BYTE *buf, UINT len) {
+ JpegDev *jd = (JpegDev *) decoder->device;
+ ESP_LOGD(__FUNCTION__, "infunc len=%d fp=%p", len, jd->fp);
+ int rlen;
+ if (buf != NULL) { /* Read nd bytes from the input strem */
+ rlen = fread(buf, 1, len, jd->fp);
+ ESP_LOGD(__FUNCTION__, "rlen=%d",rlen);
+ } else { /* Skip nd bytes on the input stream */
+ ESP_LOGD(__FUNCTION__, "buff is NULL");
+ fseek(jd->fp, len, SEEK_CUR);
+ rlen = len;
+ }
+ return rlen;
+}
+
+#define rgb565(r, g, b) (((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3))
+
+//Output function. Re-encodes the RGB888 data from the decoder as big-endian RGB565 and
+//stores it in the outData array of the JpegDev structure.
+static UINT outfunc(JDEC *decoder, void *bitmap, JRECT *rect) {
+ JpegDev *jd = (JpegDev *) decoder->device;
+ uint8_t *in = (uint8_t *) bitmap;
+ ESP_LOGD(__FUNCTION__, "rect->top=%d rect->bottom=%d", rect->top, rect->bottom);
+ ESP_LOGD(__FUNCTION__, "rect->left=%d rect->right=%d", rect->left, rect->right);
+ ESP_LOGD(__FUNCTION__, "jd->screenWidth=%d jd->screenHeight=%d", jd->screenWidth, jd->screenHeight);
+
+ for (int y = rect->top; y <= rect->bottom; y++) {
+ for (int x = rect->left; x <= rect->right; x++) {
+
+ if (y < jd->screenHeight && x < jd->screenWidth) {
+#if 0
+ jd->outData[y][x].red = in[0];
+ jd->outData[y][x].green = in[1];
+ jd->outData[y][x].blue = in[2];
+#endif
+ jd->outData[y][x] = rgb565(in[0], in[1], in[2]);
+ }
+
+ in += 3;
+ }
+ }
+ return 1;
+}
+
+// Specifies scaling factor N for output. The output image is descaled to 1 / 2 ^ N (N = 0 to 3).
+// When scaling feature is disabled (JD_USE_SCALE == 0), it must be 0.
+uint8_t getScale(uint16_t screenWidth, uint16_t screenHeight, uint16_t imageWidth, uint16_t imageHeight) {
+ if (screenWidth >= imageWidth && screenHeight >= imageHeight) return 0;
+
+ double scaleWidth = (double)imageWidth / (double)screenWidth;
+ double scaleHeight = (double)imageHeight / (double)screenHeight;
+ ESP_LOGD(__FUNCTION__, "scaleWidth=%f scaleHeight=%f", scaleWidth, scaleHeight);
+ double scale = scaleWidth;
+ if (scaleWidth < scaleHeight) scale = scaleHeight;
+ ESP_LOGD(__FUNCTION__, "scale=%f", scale);
+ if (scale <= 2.0) return 1;
+ if (scale <= 4.0) return 2;
+ return 3;
+
+}
+
+//Size of the work space for the jpeg decoder.
+#define WORKSZ 3100
+
+//Decode the embedded image into pixel lines that can be used with the rest of the logic.
+esp_err_t decode_jpeg(pixel_jpeg ***pixels, char * file, uint16_t width, uint16_t height, uint16_t * imageWidth, uint16_t * imageHeight) {
+ char *work = NULL;
+ int r;
+ JDEC decoder;
+ JpegDev jd;
+ *pixels = NULL;
+ esp_err_t ret = ESP_OK;
+
+
+ //Alocate pixel memory. Each line is an array of IMAGE_W 16-bit pixels; the `*pixels` array itself contains pointers to these lines.
+ *pixels = calloc(height, sizeof(pixel_jpeg *));
+ if (*pixels == NULL) {
+ ESP_LOGE(__FUNCTION__, "Error allocating memory for lines");
+ ret = ESP_ERR_NO_MEM;
+ goto err;
+ }
+ for (int i = 0; i < height; i++) {
+ (*pixels)[i] = malloc(width * sizeof(pixel_jpeg));
+ if ((*pixels)[i] == NULL) {
+ ESP_LOGE(__FUNCTION__, "Error allocating memory for line %d", i);
+ ret = ESP_ERR_NO_MEM;
+ goto err;
+ }
+ }
+
+ //Allocate the work space for the jpeg decoder.
+ work = calloc(WORKSZ, 1);
+ if (work == NULL) {
+ ESP_LOGE(__FUNCTION__, "Cannot allocate workspace");
+ ret = ESP_ERR_NO_MEM;
+ goto err;
+ }
+
+
+ //Populate fields of the JpegDev struct.
+ jd.outData = *pixels;
+ jd.screenWidth = width;
+ jd.screenHeight = height;
+ jd.fp = fopen(file, "rb");
+ if (jd.fp == NULL) {
+ ESP_LOGW(__FUNCTION__, "Image file not found [%s]", file);
+ ret = ESP_ERR_NOT_FOUND;
+ goto err;
+ }
+ ESP_LOGD(__FUNCTION__, "jd.fp=%p", jd.fp);
+
+ //Prepare and decode the jpeg.
+ r = jd_prepare(&decoder, infunc, work, WORKSZ, (void *) &jd);
+ if (r != JDR_OK) {
+ ESP_LOGE(__FUNCTION__, "Image decoder: jd_prepare failed (%d)", r);
+ ret = ESP_ERR_NOT_SUPPORTED;
+ goto err;
+ }
+ ESP_LOGD(__FUNCTION__, "decoder.width=%d decoder.height=%d", decoder.width, decoder.height);
+
+ //Calculate Scaling factor
+ uint8_t scale = getScale(width, height, decoder.width, decoder.height);
+ ESP_LOGD(__FUNCTION__, "scale=%d", scale);
+
+ //Calculate image size
+ double factor = 1.0;
+ if (scale == 1) factor = 0.5;
+ if (scale == 2) factor = 0.25;
+ if (scale == 3) factor = 0.125;
+ ESP_LOGD(__FUNCTION__, "factor=%f",factor);
+ *imageWidth = (double)decoder.width * factor;
+ *imageHeight = (double)decoder.height * factor;
+ ESP_LOGD(__FUNCTION__, "imageWidth=%d imageHeight=%d", *imageWidth, *imageHeight);
+
+
+ r = jd_decomp(&decoder, outfunc, scale);
+ if (r != JDR_OK) {
+ ESP_LOGE(__FUNCTION__, "Image decoder: jd_decode failed (%d)", r);
+ ret = ESP_ERR_NOT_SUPPORTED;
+ goto err;
+ }
+
+ //All done! Free the work area (as we don't need it anymore) and return victoriously.
+ free(work);
+ fclose(jd.fp);
+ return ret;
+
+ //Something went wrong! Exit cleanly, de-allocating everything we allocated.
+ err:
+ fclose(jd.fp);
+ if (*pixels != NULL) {
+ for (int i = 0; i < height; i++) {
+ free((*pixels)[i]);
+ }
+ free(*pixels);
+ }
+ free(work);
+ return ret;
+}
+
+
+esp_err_t release_image(pixel_jpeg ***pixels, uint16_t width, uint16_t height) {
+ if (*pixels != NULL) {
+ for (int i = 0; i < height; i++) {
+ free((*pixels)[i]);
+ }
+ free(*pixels);
+ }
+ return ESP_OK;
+}
+
diff --git a/main/drivers/st7789/decode_jpeg.h b/main/drivers/st7789/decode_jpeg.h
new file mode 100644
index 0000000..e69a722
--- /dev/null
+++ b/main/drivers/st7789/decode_jpeg.h
@@ -0,0 +1,34 @@
+#pragma once
+#include
+#include "esp_err.h"
+
+#if 0
+typedef struct __attribute__((__packed__)) {
+ uint8_t red;
+ uint8_t green;
+ uint8_t blue;
+} pixel_jpeg;
+#endif
+
+//rgb565 format
+typedef uint16_t pixel_jpeg;
+
+/**
+ * @brief Decode the jpeg ``image.jpg`` embedded into the program file into pixel data.
+ *
+ * @param pixels A pointer to a pointer for an array of rows, which themselves are an array of pixels.
+ * Effectively, you can get the pixel data by doing ``decode_jpeg(&myPixels); pixelval=myPixels[ypos][xpos];``
+ * @return - ESP_ERR_NOT_SUPPORTED if image is malformed or a progressive jpeg file
+ * - ESP_ERR_NO_MEM if out of memory
+ * - ESP_OK on succesful decode
+ */
+
+esp_err_t decode_jpeg(pixel_jpeg ***pixels, char * file, uint16_t width, uint16_t height, uint16_t * imageWidth, uint16_t * imageHeight);
+
+/**
+ * @brief Release image memory.
+ *
+ */
+
+esp_err_t release_image(pixel_jpeg ***pixels, uint16_t width, uint16_t height);
+
diff --git a/main/drivers/st7789/decode_png.c b/main/drivers/st7789/decode_png.c
new file mode 100644
index 0000000..9e80f63
--- /dev/null
+++ b/main/drivers/st7789/decode_png.c
@@ -0,0 +1,61 @@
+#include
+#include "decode_png.h"
+#include "pngle.h"
+#include "esp_log.h"
+
+void png_init(pngle_t *pngle, uint32_t w, uint32_t h)
+{
+ ESP_LOGD(__FUNCTION__, "png_init w=%d h=%d", w, h);
+ ESP_LOGD(__FUNCTION__, "screenWidth=%d screenHeight=%d", pngle->screenWidth, pngle->screenHeight);
+ pngle->imageWidth = w;
+ pngle->imageHeight = h;
+ pngle->reduction = false;
+ pngle->scale_factor = 1.0;
+
+ // Calculate Reduction
+ if (pngle->screenWidth < pngle->imageWidth || pngle->screenHeight < pngle->imageHeight) {
+ pngle->reduction = true;
+ double factorWidth = (double)pngle->screenWidth / (double)pngle->imageWidth;
+ double factorHeight = (double)pngle->screenHeight / (double)pngle->imageHeight;
+ pngle->scale_factor = factorWidth;
+ if (factorHeight < factorWidth) pngle->scale_factor = factorHeight;
+ pngle->imageWidth = pngle->imageWidth * pngle->scale_factor;
+ pngle->imageHeight = pngle->imageHeight * pngle->scale_factor;
+ }
+ ESP_LOGD(__FUNCTION__, "reduction=%d scale_factor=%f", pngle->reduction, pngle->scale_factor);
+ ESP_LOGD(__FUNCTION__, "imageWidth=%d imageHeight=%d", pngle->imageWidth, pngle->imageHeight);
+
+}
+
+#define rgb565(r, g, b) (((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3))
+
+void png_draw(pngle_t *pngle, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint8_t rgba[4])
+{
+ ESP_LOGD(__FUNCTION__, "png_draw x=%d y=%d w=%d h=%d", x,y,w,h);
+#if 0
+ uint8_t r = rgba[0];
+ uint8_t g = rgba[1];
+ uint8_t b = rgba[2];
+#endif
+
+ // image reduction
+ uint32_t _x = x;
+ uint32_t _y = y;
+ if (pngle->reduction) {
+ _x = x * pngle->scale_factor;
+ _y = y * pngle->scale_factor;
+ }
+ if (_y < pngle->screenHeight && _x < pngle->screenWidth) {
+#if 0
+ pngle->pixels[_y][_x].red = rgba[0];
+ pngle->pixels[_y][_x].green = rgba[1];
+ pngle->pixels[_y][_x].blue = rgba[2];
+#endif
+ pngle->pixels[_y][_x] = rgb565(rgba[0], rgba[1], rgba[2]);
+ }
+
+}
+
+void png_finish(pngle_t *pngle) {
+ ESP_LOGD(__FUNCTION__, "png_finish");
+}
diff --git a/main/drivers/st7789/decode_png.h b/main/drivers/st7789/decode_png.h
new file mode 100644
index 0000000..66365c6
--- /dev/null
+++ b/main/drivers/st7789/decode_png.h
@@ -0,0 +1,9 @@
+#pragma once
+#include
+#include
+#include "pngle.h"
+
+void png_init(pngle_t *pngle, uint32_t w, uint32_t h);
+void png_draw(pngle_t *pngle, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint8_t rgba[4]);
+void png_finish(pngle_t *pngle);
+
diff --git a/main/drivers/st7789/fontx.c b/main/drivers/st7789/fontx.c
new file mode 100644
index 0000000..c332535
--- /dev/null
+++ b/main/drivers/st7789/fontx.c
@@ -0,0 +1,582 @@
+#include
+#include
+#include
+#include
+#include "esp_err.h"
+#include "esp_log.h"
+#include "esp_spiffs.h"
+
+#include "fontx.h"
+
+#define FontxDebug 0 // for Debug
+
+// フォントファイルパスを構造体に保存
+void AddFontx(FontxFile *fx, const char *path)
+{
+ memset(fx, 0, sizeof(FontxFile));
+ fx->path = path;
+ fx->opened = false;
+}
+
+// フォント構造体を初期化
+void InitFontx(FontxFile *fxs, const char *f0, const char *f1)
+{
+ AddFontx(&fxs[0], f0);
+ AddFontx(&fxs[1], f1);
+}
+
+// フォントファイルをOPEN
+bool OpenFontx(FontxFile *fx)
+{
+ FILE *f;
+ if(!fx->opened){
+ if(FontxDebug)printf("[openFont]fx->path=[%s]\n",fx->path);
+ f = fopen(fx->path, "r");
+ if(FontxDebug)printf("[openFont]fopen=%p\n",f);
+ if (f == NULL) {
+ fx->valid = false;
+ printf("Fontx:%s not found.\n",fx->path);
+ return fx->valid ;
+ }
+ fx->opened = true;
+ fx->file = f;
+ char buf[18];
+ if (fread(buf, 1, sizeof(buf), fx->file) != sizeof(buf)) {
+ fx->valid = false;
+ printf("Fontx:%s not FONTX format.\n",fx->path);
+ fclose(fx->file);
+ return fx->valid ;
+ }
+
+ if(FontxDebug) {
+ for(int i=0;ifxname, &buf[6], 8);
+ fx->w = buf[14];
+ fx->h = buf[15];
+ fx->is_ank = (buf[16] == 0);
+ fx->bc = buf[17];
+ fx->fsz = (fx->w + 7)/8 * fx->h;
+ if(fx->fsz > FontxGlyphBufSize){
+ printf("Fontx:%s is too big font size.\n",fx->path);
+ fx->valid = false;
+ fclose(fx->file);
+ return fx->valid ;
+ }
+ fx->valid = true;
+ }
+ return fx->valid;
+}
+
+// フォントファイルをCLOSE
+void CloseFontx(FontxFile *fx)
+{
+ if(fx->opened){
+ fclose(fx->file);
+ fx->opened = false;
+ }
+}
+
+// フォント構造体の表示
+void DumpFontx(FontxFile *fxs)
+{
+ for(int i=0;i<2;i++) {
+ printf("fxs[%d]->path=%s\n",i,fxs[i].path);
+ printf("fxs[%d]->opened=%d\n",i,fxs[i].opened);
+ printf("fxs[%d]->fxname=%s\n",i,fxs[i].fxname);
+ printf("fxs[%d]->valid=%d\n",i,fxs[i].valid);
+ printf("fxs[%d]->is_ank=%d\n",i,fxs[i].is_ank);
+ printf("fxs[%d]->w=%d\n",i,fxs[i].w);
+ printf("fxs[%d]->h=%d\n",i,fxs[i].h);
+ printf("fxs[%d]->fsz=%d\n",i,fxs[i].fsz);
+ printf("fxs[%d]->bc=%d\n",i,fxs[i].bc);
+ }
+}
+
+uint8_t getFortWidth(FontxFile *fx) {
+ printf("fx->w=%d\n",fx->w);
+ return(fx->w);
+}
+
+uint8_t getFortHeight(FontxFile *fx) {
+ printf("fx->h=%d\n",fx->h);
+ return(fx->h);
+}
+
+
+/*
+ フォントファイルからフォントパターンを取り出す
+
+ フォントの並び(16X16ドット)
+ 00000000 01111111
+ 12345678 90123456
+ 01 pGlyph[000] pGlyph[001]
+ 02 pGlyph[002] pGlyph[003]
+ 03 pGlyph[004] pGlyph[005]
+ 04 pGlyph[006] pGlyph[007]
+ 05 pGlyph[008] pGlyph[009]
+ 06 pGlyph[010] pGlyph[011]
+ 07 pGlyph[012] pGlyph[013]
+ 08 pGlyph[014] pGlyph[015]
+ 09 pGlyph[016] pGlyph[017]
+ 10 pGlyph[018] pGlyph[019]
+ 11 pGlyph[020] pGlyph[021]
+ 12 pGlyph[022] pGlyph[023]
+ 13 pGlyph[024] pGlyph[025]
+ 14 pGlyph[026] pGlyph[027]
+ 15 pGlyph[028] pGlyph[029]
+ 16 pGlyph[030] pGlyph[031]
+
+ フォントの並び(24X24ドット)
+ 00000000 01111111 11122222
+ 12345678 90123456 78901234
+ 01 pGlyph[000] pGlyph[001] pGlyph[002]
+ 02 pGlyph[003] pGlyph[004] pGlyph[005]
+ 03 pGlyph[006] pGlyph[007] pGlyph[008]
+ 04 pGlyph[009] pGlyph[010] pGlyph[011]
+ 05 pGlyph[012] pGlyph[013] pGlyph[014]
+ 06 pGlyph[015] pGlyph[016] pGlyph[017]
+ 07 pGlyph[018] pGlyph[019] pGlyph[020]
+ 08 pGlyph[021] pGlyph[022] pGlyph[023]
+ 09 pGlyph[024] pGlyph[025] pGlyph[026]
+ 10 pGlyph[027] pGlyph[028] pGlyph[029]
+ 11 pGlyph[030] pGlyph[031] pGlyph[032]
+ 12 pGlyph[033] pGlyph[034] pGlyph[035]
+ 13 pGlyph[036] pGlyph[037] pGlyph[038]
+ 14 pGlyph[039] pGlyph[040] pGlyph[041]
+ 15 pGlyph[042] pGlyph[043] pGlyph[044]
+ 16 pGlyph[045] pGlyph[046] pGlyph[047]
+ 17 pGlyph[048] pGlyph[049] pGlyph[050]
+ 18 pGlyph[051] pGlyph[052] pGlyph[053]
+ 19 pGlyph[054] pGlyph[055] pGlyph[056]
+ 20 pGlyph[057] pGlyph[058] pGlyph[059]
+ 21 pGlyph[060] pGlyph[061] pGlyph[062]
+ 22 pGlyph[063] pGlyph[064] pGlyph[065]
+ 23 pGlyph[066] pGlyph[067] pGlyph[068]
+ 24 pGlyph[069] pGlyph[070] pGlyph[071]
+
+ フォントの並び(32X32ドット)
+ 00000000 01111111 11122222 22222333
+ 12345678 90123456 78901234 56789012
+ 01 pGlyph[000] pGlyph[001] pGlyph[002] pGlyph[003]
+ 02 pGlyph[004] pGlyph[005] pGlyph[006] pGlyph[007]
+ 03 pGlyph[008] pGlyph[009] pGlyph[010] pGlyph[011]
+ 04 pGlyph[012] pGlyph[013] pGlyph[014] pGlyph[015]
+ 05 pGlyph[016] pGlyph[017] pGlyph[018] pGlyph[019]
+ 06 pGlyph[020] pGlyph[021] pGlyph[022] pGlyph[023]
+ 07 pGlyph[024] pGlyph[025] pGlyph[026] pGlyph[027]
+ 08 pGlyph[028] pGlyph[029] pGlyph[030] pGlyph[031]
+ 09 pGlyph[032] pGlyph[033] pGlyph[034] pGlyph[035]
+ 10 pGlyph[036] pGlyph[037] pGlyph[038] pGlyph[039]
+ 11 pGlyph[040] pGlyph[041] pGlyph[042] pGlyph[043]
+ 12 pGlyph[044] pGlyph[045] pGlyph[046] pGlyph[047]
+ 13 pGlyph[048] pGlyph[049] pGlyph[050] pGlyph[051]
+ 14 pGlyph[052] pGlyph[053] pGlyph[054] pGlyph[055]
+ 15 pGlyph[056] pGlyph[057] pGlyph[058] pGlyph[059]
+ 16 pGlyph[060] pGlyph[061] pGlyph[062] pGlyph[063]
+ 17 pGlyph[064] pGlyph[065] pGlyph[066] pGlyph[067]
+ 18 pGlyph[068] pGlyph[069] pGlyph[070] pGlyph[071]
+ 19 pGlyph[072] pGlyph[073] pGlyph[074] pGlyph[075]
+ 20 pGlyph[076] pGlyph[077] pGlyph[078] pGlyph[079]
+ 21 pGlyph[080] pGlyph[081] pGlyph[082] pGlyph[083]
+ 22 pGlyph[084] pGlyph[085] pGlyph[086] pGlyph[087]
+ 23 pGlyph[088] pGlyph[089] pGlyph[090] pGlyph[091]
+ 24 pGlyph[092] pGlyph[093] pGlyph[094] pGlyph[095]
+ 25 pGlyph[096] pGlyph[097] pGlyph[098] pGlyph[099]
+ 26 pGlyph[100] pGlyph[101] pGlyph[102] pGlyph[103]
+ 27 pGlyph[104] pGlyph[105] pGlyph[106] pGlyph[107]
+ 28 pGlyph[108] pGlyph[109] pGlyph[110] pGlyph[111]
+ 29 pGlyph[112] pGlyph[113] pGlyph[114] pGlyph[115]
+ 30 pGlyph[116] pGlyph[117] pGlyph[118] pGlyph[119]
+ 31 pGlyph[120] pGlyph[121] pGlyph[122] pGlyph[123]
+ 32 pGlyph[124] pGlyph[125] pGlyph[127] pGlyph[128]
+
+*/
+
+bool GetFontx(FontxFile *fxs, uint8_t ascii , uint8_t *pGlyph, uint8_t *pw, uint8_t *ph)
+{
+
+ int i;
+ uint32_t offset;
+
+ if(FontxDebug)printf("[GetFontx]ascii=0x%x\n",ascii);
+ for(i=0; i<2; i++){
+ //for(i=0; i<1; i++){
+ if(!OpenFontx(&fxs[i])) continue;
+ if(FontxDebug)printf("[GetFontx]openFontxFile[%d] ok\n",i);
+
+ //if(ascii < 0xFF){
+ if(fxs[i].is_ank){
+ if(FontxDebug)printf("[GetFontx]fxs.is_ank fxs.fsz=%d\n",fxs[i].fsz);
+ offset = 17 + ascii * fxs[i].fsz;
+ if(FontxDebug)printf("[GetFontx]offset=%d\n",offset);
+ if(fseek(fxs[i].file, offset, SEEK_SET)) {
+ printf("Fontx:seek(%u) failed.\n",offset);
+ return false;
+ }
+ if(fread(pGlyph, 1, fxs[i].fsz, fxs[i].file) != fxs[i].fsz) {
+ printf("Fontx:fread failed.\n");
+ return false;
+ }
+ if(pw) *pw = fxs[i].w;
+ if(ph) *ph = fxs[i].h;
+ return true;
+ }
+ //}
+ }
+ return false;
+}
+
+
+/*
+ フォントパターンをビットマップイメージに変換する
+
+ fonts(16X16ドット)
+ 00000000 01111111
+ 12345678 90123456
+ 01 pGlyph[000] pGlyph[001]
+ 02 pGlyph[002] pGlyph[003]
+ 03 pGlyph[004] pGlyph[005]
+ 04 pGlyph[006] pGlyph[007]
+ 05 pGlyph[008] pGlyph[009]
+ 06 pGlyph[010] pGlyph[011]
+ 07 pGlyph[012] pGlyph[013]
+ 08 pGlyph[014] pGlyph[015]
+ 09 pGlyph[016] pGlyph[017]
+ 10 pGlyph[018] pGlyph[019]
+ 11 pGlyph[020] pGlyph[021]
+ 12 pGlyph[022] pGlyph[023]
+ 13 pGlyph[024] pGlyph[025]
+ 14 pGlyph[026] pGlyph[027]
+ 15 pGlyph[028] pGlyph[029]
+ 16 pGlyph[030] pGlyph[031]
+
+ line[32*4]
+ 01 line[000] line[001] line[002] .... line[014] line[015] line[016-031](Not use)
+ |
+ 07 line[000] line[001] line[002] .... line[014] line[015] line[016-031](Not use)
+
+ 08 line[032] line[033] line[034] .... line[046] line[047] line[048-063](Not use)
+ |
+ 16 line[032] line[033] line[034] .... line[046] line[047] line[048-063](Not use)
+
+
+
+ fonts(24X24ドット)
+ 00000000 01111111 11122222
+ 12345678 90123456 78901234
+ 01 pGlyph[000] pGlyph[001] pGlyph[002]
+ 02 pGlyph[003] pGlyph[004] pGlyph[005]
+ 03 pGlyph[006] pGlyph[007] pGlyph[008]
+ 04 pGlyph[009] pGlyph[010] pGlyph[011]
+ 05 pGlyph[012] pGlyph[013] pGlyph[014]
+ 06 pGlyph[015] pGlyph[016] pGlyph[017]
+ 07 pGlyph[018] pGlyph[019] pGlyph[020]
+ 08 pGlyph[021] pGlyph[022] pGlyph[023]
+ 09 pGlyph[024] pGlyph[025] pGlyph[026]
+ 10 pGlyph[027] pGlyph[028] pGlyph[029]
+ 11 pGlyph[030] pGlyph[031] pGlyph[032]
+ 12 pGlyph[033] pGlyph[034] pGlyph[035]
+ 13 pGlyph[036] pGlyph[037] pGlyph[038]
+ 14 pGlyph[039] pGlyph[040] pGlyph[041]
+ 15 pGlyph[042] pGlyph[043] pGlyph[044]
+ 16 pGlyph[045] pGlyph[046] pGlyph[047]
+ 17 pGlyph[048] pGlyph[049] pGlyph[050]
+ 18 pGlyph[051] pGlyph[052] pGlyph[053]
+ 19 pGlyph[054] pGlyph[055] pGlyph[056]
+ 20 pGlyph[057] pGlyph[058] pGlyph[059]
+ 21 pGlyph[060] pGlyph[061] pGlyph[062]
+ 22 pGlyph[063] pGlyph[064] pGlyph[065]
+ 23 pGlyph[066] pGlyph[067] pGlyph[068]
+ 24 pGlyph[069] pGlyph[070] pGlyph[071]
+
+ line[32*4]
+ 01 line[000] line[001] line[002] .... line[022] line[023] line[024-031](Not use)
+ |
+ 08 line[000] line[001] line[002] .... line[022] line[023] line[024-031](Not use)
+
+ 09 line[032] line[033] line[034] .... line[054] line[055] line[056-063](Not use)
+ |
+ 16 line[032] line[033] line[034] .... line[054] line[055] line[056-063](Not use)
+
+ 17 line[064] line[065] line[066] .... line[086] line[087] line[088-095](Not use)
+ |
+ 24 line[064] line[065] line[066] .... line[086] line[087] line[088-095](Not use)
+
+
+ fonts(32X32ドット)
+ 00000000 01111111 11122222 22222333
+ 12345678 90123456 78901234 56789012
+ 01 pGlyph[000] pGlyph[001] pGlyph[002] pGlyph[003]
+ 02 pGlyph[004] pGlyph[005] pGlyph[006] pGlyph[007]
+ 03 pGlyph[008] pGlyph[009] pGlyph[010] pGlyph[011]
+ 04 pGlyph[012] pGlyph[013] pGlyph[014] pGlyph[015]
+ 05 pGlyph[016] pGlyph[017] pGlyph[018] pGlyph[019]
+ 06 pGlyph[020] pGlyph[021] pGlyph[022] pGlyph[023]
+ 07 pGlyph[024] pGlyph[025] pGlyph[026] pGlyph[027]
+ 08 pGlyph[028] pGlyph[029] pGlyph[030] pGlyph[031]
+ 09 pGlyph[032] pGlyph[033] pGlyph[034] pGlyph[035]
+ 10 pGlyph[036] pGlyph[037] pGlyph[038] pGlyph[039]
+ 11 pGlyph[040] pGlyph[041] pGlyph[042] pGlyph[043]
+ 12 pGlyph[044] pGlyph[045] pGlyph[046] pGlyph[047]
+ 13 pGlyph[048] pGlyph[049] pGlyph[050] pGlyph[051]
+ 14 pGlyph[052] pGlyph[053] pGlyph[054] pGlyph[055]
+ 15 pGlyph[056] pGlyph[057] pGlyph[058] pGlyph[059]
+ 16 pGlyph[060] pGlyph[061] pGlyph[062] pGlyph[063]
+ 17 pGlyph[064] pGlyph[065] pGlyph[066] pGlyph[067]
+ 18 pGlyph[068] pGlyph[069] pGlyph[070] pGlyph[071]
+ 19 pGlyph[072] pGlyph[073] pGlyph[074] pGlyph[075]
+ 20 pGlyph[076] pGlyph[077] pGlyph[078] pGlyph[079]
+ 21 pGlyph[080] pGlyph[081] pGlyph[082] pGlyph[083]
+ 22 pGlyph[084] pGlyph[085] pGlyph[086] pGlyph[087]
+ 23 pGlyph[088] pGlyph[089] pGlyph[090] pGlyph[091]
+ 24 pGlyph[092] pGlyph[093] pGlyph[094] pGlyph[095]
+ 25 pGlyph[096] pGlyph[097] pGlyph[098] pGlyph[099]
+ 26 pGlyph[100] pGlyph[101] pGlyph[102] pGlyph[103]
+ 27 pGlyph[104] pGlyph[105] pGlyph[106] pGlyph[107]
+ 28 pGlyph[108] pGlyph[109] pGlyph[110] pGlyph[111]
+ 29 pGlyph[112] pGlyph[113] pGlyph[114] pGlyph[115]
+ 30 pGlyph[116] pGlyph[117] pGlyph[118] pGlyph[119]
+ 31 pGlyph[120] pGlyph[121] pGlyph[122] pGlyph[123]
+ 32 pGlyph[124] pGlyph[125] pGlyph[127] pGlyph[128]
+
+ line[32*4]
+ 01 line[000] line[001] line[002] .... line[030] line[031]
+ |
+ 08 line[000] line[001] line[002] .... line[030] line[031]
+
+ 09 line[032] line[033] line[034] .... line[062] line[063]
+ |
+ 16 line[032] line[033] line[034] .... line[062] line[063]
+
+ 17 line[064] line[065] line[066] .... line[094] line[095]
+ |
+ 24 line[064] line[065] line[066] .... line[094] line[095]
+
+ 25 line[096] line[097] line[098] .... line[126] line[127]
+ |
+ 32 line[096] line[097] line[098] .... line[126] line[127]
+
+*/
+void Font2Bitmap(uint8_t *fonts, uint8_t *line, uint8_t w, uint8_t h, uint8_t inverse) {
+ int x,y;
+ for(y=0; y<(h/8); y++){
+ for(x=0; x> (x % 8))) line[linep] = line[linep] + (1 << mask);
+ }
+ mask--;
+ if (mask < 0) mask = 7;
+ fontp += (w + 7)/8;
+ }
+
+ if (inverse) {
+ for(y=0; y<(h/8); y++){
+ for(x=0; x> (x % 8))) {
+ printf("*");
+ } else {
+ printf(".");
+ }
+ }
+ printf("\n");
+ fpos=fpos+(pw+7)/8;
+ }
+ printf("\n");
+}
+
+// Bitmapの表示
+void ShowBitmap(uint8_t *bitmap, uint8_t pw, uint8_t ph) {
+ int x,y,fpos;
+ printf("[ShowBitmap pw=%d ph=%d]\n",pw,ph);
+#if 0
+ for (y=0;y<(ph+7)/8;y++) {
+ for (x=0;x> fpos);
+ if (bitmap[x+(y/8)*32] & (0x80 >> fpos)) {
+ printf("*");
+ } else {
+ printf(".");
+ }
+ }
+ printf("\n");
+ fpos++;
+ if (fpos > 7) fpos = 0;
+ }
+ printf("\n");
+}
+
+
+// 8ビットデータを反転
+uint8_t RotateByte(uint8_t ch1) {
+ uint8_t ch2 = 0;
+ int j;
+ for (j=0;j<8;j++) {
+ ch2 = (ch2 << 1) + (ch1 & 0x01);
+ ch1 = ch1 >> 1;
+ }
+ return ch2;
+}
+
+
+#if 0
+// UTF code(3Byte) を SJIS Code(2 Byte) に変換
+// https://www.mgo-tec.com/blog-entry-utf8sjis01.html
+uint16_t UTF2SJIS(spiffs_file fd, uint8_t *utf8) {
+
+ uint32_t offset = 0;
+ uint32_t ret;
+ uint32_t UTF8uint = utf8[0]*256*256 + utf8[1]*256 + utf8[2];
+
+ if(utf8[0]>=0xC2 && utf8[0]<=0xD1){ //0xB0からS_JISコード実データ。0x00-0xAFまではライセンス文ヘッダなのでそれをカット。
+ offset = ((utf8[0]*256 + utf8[1])-0xC2A2)*2 + 0xB0; //文字"¢" UTF8コード C2A2~、S_jisコード8191
+ }else if(utf8[0]==0xE2 && utf8[1]>=0x80){
+ offset = (UTF8uint-0xE28090)*2 + 0x1EEC; //文字"‐" UTF8コード E28090~、S_jisコード815D
+ }else if(utf8[0]==0xE3 && utf8[1]>=0x80){
+ offset = (UTF8uint-0xE38080)*2 + 0x9DCC; //スペース UTF8コード E38080~、S_jisコード8140
+ }else if(utf8[0]==0xE4 && utf8[1]>=0x80){
+ offset = (UTF8uint-0xE4B880)*2 + 0x11CCC; //文字"一" UTF8コード E4B880~、S_jisコード88EA
+ }else if(utf8[0]==0xE5 && utf8[1]>=0x80){
+ offset = (UTF8uint-0xE58085)*2 + 0x12BCC; //文字"倅" UTF8コード E58085~、S_jisコード98E4
+ }else if(utf8[0]==0xE6 && utf8[1]>=0x80){
+ offset = (UTF8uint-0xE6808E)*2 + 0x1AAC2; //文字"怎" UTF8コード E6808E~、S_jisコード9C83
+ }else if(utf8[0]==0xE7 && utf8[1]>=0x80){
+ offset = (UTF8uint-0xE78081)*2 + 0x229A6; //文字"瀁" UTF8コード E78081~、S_jisコードE066
+ }else if(utf8[0]==0xE8 && utf8[1]>=0x80){
+ offset = (UTF8uint-0xE88080)*2 + 0x2A8A4; //文字"耀" UTF8コード E88080~、S_jisコード9773
+ }else if(utf8[0]==0xE9 && utf8[1]>=0x80){
+ offset = (UTF8uint-0xE98080)*2 + 0x327A4; //文字"退" UTF8コード E98080~、S_jisコード91DE
+ }else if(utf8[0]>=0xEF && utf8[1]>=0xBC){
+ offset = (UTF8uint-0xEFBC81)*2 + 0x3A6A4; //文字"!" UTF8コード EFBC81~、S_jisコード8149
+ if(utf8[0]==0xEF && utf8[1]==0xBD && utf8[2]==0x9E){
+ offset = 0x3A8DE; // "~" UTF8コード EFBD9E、S_jisコード8160
+ }
+ }
+
+if(FontxDebug)printf("[UTF2SJIS] offset=%d\n",offset);
+ char buf[2];
+ ret = SPIFFS_lseek(&fs, fd, offset, SPIFFS_SEEK_SET);
+if(FontxDebug)printf("[UTF2SJIS] lseek ret=%d\n",ret);
+ if (ret != offset) {
+ printf("UTF2SJIS:seek(%u) failed.\n",offset);
+ return 0;
+ }
+ if (SPIFFS_read(&fs, fd, buf, sizeof(buf)) != sizeof(buf)) {
+ printf("UTF2SJIS:read failed.\n");
+ return 0;
+ }
+if(FontxDebug)printf("[UTF2SJIS] sjis=0x%x%x\n",buf[0],buf[1]);
+ return buf[0]*256+buf[1];
+}
+
+
+// UTFを含む文字列をSJISに変換
+int String2SJIS(spiffs_file fd, unsigned char *str_in, size_t stlen,
+ uint16_t *sjis, size_t ssize) {
+ int i;
+ uint8_t sp;
+ uint8_t c1 = 0;
+ uint8_t c2 = 0;
+ uint8_t utf8[3];
+ uint16_t sjis2;
+ int spos = 0;
+
+ for(i=0;i
+#include
+#include
+#include
+#include
+
+#include "esp_log.h"
+//#include "miniz.h"
+#include "esp32/rom/miniz.h"
+#include "pngle.h"
+
+#define PNGLE_ERROR(s) (pngle->error = (s), pngle->state = PNGLE_STATE_ERROR, -1)
+#define PNGLE_CALLOC(a, b, name) (debug_printf("[pngle] Allocating %zu bytes for %s\n", (size_t)(a) * (size_t)(b), (name)), calloc((size_t)(a), (size_t)(b)))
+
+#define PNGLE_UNUSED(x) (void)(x)
+
+// magic
+static const uint8_t png_sig[] = { 137, 80, 78, 71, 13, 10, 26, 10 };
+static uint32_t interlace_off_x[8] = { 0, 0, 4, 0, 2, 0, 1, 0 };
+static uint32_t interlace_off_y[8] = { 0, 0, 0, 4, 0, 2, 0, 1 };
+static uint32_t interlace_div_x[8] = { 1, 8, 8, 4, 4, 2, 2, 1 };
+static uint32_t interlace_div_y[8] = { 1, 8, 8, 8, 4, 4, 2, 2 };
+
+
+static inline uint8_t read_uint8(const uint8_t *p)
+{
+ return *p;
+}
+
+static inline uint32_t read_uint32(const uint8_t *p)
+{
+ return (p[0] << 24)
+ | (p[1] << 16)
+ | (p[2] << 8)
+ | (p[3] << 0)
+ ;
+}
+
+static inline uint32_t U32_CLAMP_ADD(uint32_t a, uint32_t b, uint32_t top)
+{
+ uint32_t v = a + b;
+ if (v < a) return top; // uint32 overflow
+ if (v > top) return top; // clamp
+ return v;
+}
+
+
+void pngle_reset(pngle_t *pngle)
+{
+ if (!pngle) return ;
+
+ pngle->state = PNGLE_STATE_INITIAL;
+ pngle->error = "No error";
+
+ if (pngle->scanline_ringbuf) free(pngle->scanline_ringbuf);
+ if (pngle->palette) free(pngle->palette);
+ if (pngle->trans_palette) free(pngle->trans_palette);
+#ifndef PNGLE_NO_GAMMA_CORRECTION
+ if (pngle->gamma_table) free(pngle->gamma_table);
+#endif
+
+ pngle->scanline_ringbuf = NULL;
+ pngle->palette = NULL;
+ pngle->trans_palette = NULL;
+#ifndef PNGLE_NO_GAMMA_CORRECTION
+ pngle->gamma_table = NULL;
+#endif
+
+ pngle->channels = 0; // indicates IHDR hasn't been processed yet
+ pngle->next_out = NULL; // indicates IDAT hasn't been processed yet
+
+ // clear them just in case...
+ memset(&pngle->hdr, 0, sizeof(pngle->hdr));
+ pngle->n_palettes = 0;
+ pngle->n_trans_palettes = 0;
+
+ tinfl_init(&pngle->inflator);
+}
+
+pngle_t *pngle_new(uint16_t width, uint16_t height)
+{
+ pngle_t *pngle = (pngle_t *)PNGLE_CALLOC(1, sizeof(pngle_t), "pngle_t");
+ if (!pngle) return NULL;
+
+ pngle_reset(pngle);
+
+ pngle->pixels = NULL;
+
+ //Alocate pixel memory. Each line is an array of IMAGE_W 16-bit pixels; the `*pixels` array itself contains pointers to these lines.
+ ESP_LOGD(__FUNCTION__, "height=%d sizeof(pixel_png *)=%d", height, sizeof(pixel_png *));
+ pngle->pixels = calloc(height, sizeof(pixel_png *));
+ if (pngle->pixels == NULL) {
+ ESP_LOGE(__FUNCTION__, "Error allocating memory for lines");
+ //ret = ESP_ERR_NO_MEM;
+ goto err;
+ }
+ ESP_LOGD(__FUNCTION__, "width=%d sizeof(pixel_png)=%d", width, sizeof(pixel_png));
+ for (int i = 0; i < height; i++) {
+ (pngle->pixels)[i] = malloc(width * sizeof(pixel_png));
+ if ((pngle->pixels)[i] == NULL) {
+ ESP_LOGE(__FUNCTION__, "Error allocating memory for line %d", i);
+ //ret = ESP_ERR_NO_MEM;
+ goto err;
+ }
+ }
+
+ pngle->screenWidth = width;
+ pngle->screenHeight = height;
+ return pngle;
+
+ err:
+ //Something went wrong! Exit cleanly, de-allocating everything we allocated.
+ if (pngle->pixels != NULL) {
+ for (int i = 0; i < height; i++) {
+ free((pngle->pixels)[i]);
+ }
+ free(pngle->pixels);
+ }
+ return NULL;
+}
+
+void pngle_destroy(pngle_t *pngle, uint16_t width, uint16_t height)
+{
+ if (pngle) {
+ if (pngle->pixels != NULL) {
+ for (int i = 0; i < height; i++) {
+ free((pngle->pixels)[i]);
+ }
+ free(pngle->pixels);
+ }
+ pngle_reset(pngle);
+ free(pngle);
+ }
+}
+
+const char *pngle_error(pngle_t *pngle)
+{
+ if (!pngle) return "Uninitialized";
+ return pngle->error;
+}
+
+uint32_t pngle_get_width(pngle_t *pngle)
+{
+ if (!pngle) return 0;
+ return pngle->hdr.width;
+}
+
+uint32_t pngle_get_height(pngle_t *pngle)
+{
+ if (!pngle) return 0;
+ return pngle->hdr.height;
+}
+
+pngle_ihdr_t *pngle_get_ihdr(pngle_t *pngle)
+{
+ if (!pngle) return NULL;
+ if (pngle->channels == 0) return NULL;
+ return &pngle->hdr;
+}
+
+
+static int is_trans_color(pngle_t *pngle, uint16_t *value, size_t n)
+{
+ if (pngle->n_trans_palettes != 1) return 0; // false (none or indexed)
+
+ for (size_t i = 0; i < n; i++) {
+ if (value[i] != (pngle->trans_palette[i * 2 + 0] * 0x100 + pngle->trans_palette[i * 2 + 1])) return 0; // false
+ }
+ return 1; // true
+}
+
+static inline void scanline_ringbuf_push(pngle_t *pngle, uint8_t value)
+{
+ pngle->scanline_ringbuf[pngle->scanline_ringbuf_cidx] = value;
+ pngle->scanline_ringbuf_cidx = (pngle->scanline_ringbuf_cidx + 1) % pngle->scanline_ringbuf_size;
+}
+
+static inline uint16_t get_value(pngle_t *pngle, size_t *ridx, int *bitcount, int depth)
+{
+ uint16_t v;
+
+ switch (depth) {
+ case 1:
+ case 2:
+ case 4:
+ if (*bitcount >= 8) {
+ *bitcount = 0;
+ *ridx = (*ridx + 1) % pngle->scanline_ringbuf_size;
+ }
+ *bitcount += depth;
+ uint8_t mask = ((1UL << depth) - 1);
+ uint8_t shift = (8 - *bitcount);
+ return (pngle->scanline_ringbuf[*ridx] >> shift) & mask;
+
+ case 8:
+ v = pngle->scanline_ringbuf[*ridx];
+ *ridx = (*ridx + 1) % pngle->scanline_ringbuf_size;
+ return v;
+
+ case 16:
+ v = pngle->scanline_ringbuf[*ridx];
+ *ridx = (*ridx + 1) % pngle->scanline_ringbuf_size;
+
+ v = v * 0x100 + pngle->scanline_ringbuf[*ridx];
+ *ridx = (*ridx + 1) % pngle->scanline_ringbuf_size;
+ return v;
+ }
+
+ return 0;
+}
+
+static int pngle_draw_pixels(pngle_t *pngle, size_t scanline_ringbuf_xidx)
+{
+ uint16_t v[4]; // MAX_CHANNELS
+ int bitcount = 0;
+ uint8_t pixel_depth = (pngle->hdr.color_type & 1) ? 8 : pngle->hdr.depth;
+ uint16_t maxval = (1UL << pixel_depth) - 1;
+
+ int n_pixels = pngle->hdr.depth == 16 ? 1 : (8 / pngle->hdr.depth);
+
+ for (; n_pixels-- > 0 && pngle->drawing_x < pngle->hdr.width; pngle->drawing_x = U32_CLAMP_ADD(pngle->drawing_x, interlace_div_x[pngle->interlace_pass], pngle->hdr.width)) {
+ for (uint_fast8_t c = 0; c < pngle->channels; c++) {
+ v[c] = get_value(pngle, &scanline_ringbuf_xidx, &bitcount, pngle->hdr.depth);
+ }
+
+ // color type: 0000 0111
+ // ^-- indexed color (palette)
+ // ^--- Color
+ // ^---- Alpha channel
+
+ if (pngle->hdr.color_type & 2) {
+ // color
+ if (pngle->hdr.color_type & 1) {
+ // indexed color: type 3
+
+ // lookup palette info
+ uint16_t pidx = v[0];
+ if (pidx >= pngle->n_palettes) return PNGLE_ERROR("Color index is out of range");
+
+ v[0] = pngle->palette[pidx * 3 + 0];
+ v[1] = pngle->palette[pidx * 3 + 1];
+ v[2] = pngle->palette[pidx * 3 + 2];
+
+ // tRNS as an indexed alpha value table (for color type 3)
+ v[3] = pidx < pngle->n_trans_palettes ? pngle->trans_palette[pidx] : maxval;
+ } else {
+ // true color: 2, and 6
+ v[3] = (pngle->hdr.color_type & 4) ? v[3] : is_trans_color(pngle, v, 3) ? 0 : maxval;
+ }
+ } else {
+ // alpha, tRNS, or opaque
+ v[3] = (pngle->hdr.color_type & 4) ? v[1] : is_trans_color(pngle, v, 1) ? 0 : maxval;
+
+ // monochrome
+ v[1] = v[2] = v[0];
+ }
+
+ if (pngle->draw_callback) {
+ uint8_t rgba[4] = {
+ (v[0] * 255 + maxval / 2) / maxval,
+ (v[1] * 255 + maxval / 2) / maxval,
+ (v[2] * 255 + maxval / 2) / maxval,
+ (v[3] * 255 + maxval / 2) / maxval
+ };
+
+#ifndef PNGLE_NO_GAMMA_CORRECTION
+ if (pngle->gamma_table) {
+ for (int i = 0; i < 3; i++) {
+ rgba[i] = pngle->gamma_table[v[i]];
+ }
+ }
+#endif
+
+ pngle->draw_callback(pngle, pngle->drawing_x, pngle->drawing_y
+ , MIN(interlace_div_x[pngle->interlace_pass] - interlace_off_x[pngle->interlace_pass], pngle->hdr.width - pngle->drawing_x)
+ , MIN(interlace_div_y[pngle->interlace_pass] - interlace_off_y[pngle->interlace_pass], pngle->hdr.height - pngle->drawing_y)
+ , rgba
+ );
+ }
+ }
+
+ return 0;
+}
+
+static inline int paeth(int a, int b, int c)
+{
+ int p = a + b - c;
+ int pa = abs(p - a);
+ int pb = abs(p - b);
+ int pc = abs(p - c);
+
+ if (pa <= pb && pa <= pc) return a;
+ if (pb <= pc) return b;
+ return c;
+}
+
+static int set_interlace_pass(pngle_t *pngle, uint_fast8_t pass)
+{
+ pngle->interlace_pass = pass;
+
+ uint_fast8_t bytes_per_pixel = (pngle->channels * pngle->hdr.depth + 7) / 8; // 1 if depth <= 8
+ size_t scanline_pixels = (pngle->hdr.width - interlace_off_x[pngle->interlace_pass] + interlace_div_x[pngle->interlace_pass] - 1) / interlace_div_x[pngle->interlace_pass];
+ size_t scanline_stride = (scanline_pixels * pngle->channels * pngle->hdr.depth + 7) / 8;
+
+ pngle->scanline_ringbuf_size = scanline_stride + bytes_per_pixel * 2; // 2 rooms for c/x and a
+
+ if (pngle->scanline_ringbuf) free(pngle->scanline_ringbuf);
+ if ((pngle->scanline_ringbuf = PNGLE_CALLOC(pngle->scanline_ringbuf_size, 1, "scanline ringbuf")) == NULL) return PNGLE_ERROR("Insufficient memory");
+
+ pngle->drawing_x = interlace_off_x[pngle->interlace_pass];
+ pngle->drawing_y = interlace_off_y[pngle->interlace_pass];
+ pngle->filter_type = -1;
+
+ pngle->scanline_ringbuf_cidx = 0;
+ pngle->scanline_remain_bytes_to_render = -1;
+
+ return 0;
+}
+
+static int setup_gamma_table(pngle_t *pngle, uint32_t png_gamma)
+{
+#ifndef PNGLE_NO_GAMMA_CORRECTION
+ if (pngle->gamma_table) free(pngle->gamma_table);
+
+ if (pngle->display_gamma <= 0) return 0; // disable gamma correction
+ if (png_gamma == 0) return 0;
+
+ uint8_t pixel_depth = (pngle->hdr.color_type & 1) ? 8 : pngle->hdr.depth;
+ uint16_t maxval = (1UL << pixel_depth) - 1;
+
+ pngle->gamma_table = PNGLE_CALLOC(1, maxval + 1, "gamma table");
+ if (!pngle->gamma_table) return PNGLE_ERROR("Insufficient memory");
+
+ for (int i = 0; i < maxval + 1; i++) {
+ pngle->gamma_table[i] = (uint8_t)floor(pow(i / (double)maxval, 100000.0 / png_gamma / pngle->display_gamma) * 255.0 + 0.5);
+ }
+ debug_printf("[pngle] gamma value = %d\n", png_gamma);
+#else
+ PNGLE_UNUSED(pngle);
+ PNGLE_UNUSED(png_gamma);
+#endif
+ return 0;
+}
+
+
+static int pngle_on_data(pngle_t *pngle, const uint8_t *p, int len)
+{
+ const uint8_t *ep = p + len;
+
+ uint_fast8_t bytes_per_pixel = (pngle->channels * pngle->hdr.depth + 7) / 8; // 1 if depth <= 8
+
+ while (p < ep) {
+ if (pngle->drawing_x >= pngle->hdr.width) {
+ // New row
+ pngle->drawing_x = interlace_off_x[pngle->interlace_pass];
+ pngle->drawing_y = U32_CLAMP_ADD(pngle->drawing_y, interlace_div_y[pngle->interlace_pass], pngle->hdr.height);
+ pngle->filter_type = -1; // Indicate new line
+ }
+
+ if (pngle->drawing_x >= pngle->hdr.width || pngle->drawing_y >= pngle->hdr.height) {
+ if (pngle->interlace_pass == 0 || pngle->interlace_pass >= 7) return len; // Do nothing further
+
+ // Interlace: Next pass
+ if (set_interlace_pass(pngle, pngle->interlace_pass + 1) < 0) return -1;
+ debug_printf("[pngle] interlace pass changed to: %d\n", pngle->interlace_pass);
+
+ continue; // This is required because "No filter type bytes are present in an empty pass".
+ }
+
+ if (pngle->filter_type < 0) {
+ if (*p > 4) {
+ debug_printf("[pngle] Invalid filter type is found; 0x%02x\n", *p);
+ return PNGLE_ERROR("Invalid filter type is found");
+ }
+
+ pngle->filter_type = (int_fast8_t)*p++; // 0 - 4
+
+ // push sentinel bytes for new line
+ for (uint_fast8_t i = 0; i < bytes_per_pixel; i++) {
+ scanline_ringbuf_push(pngle, 0);
+ }
+
+ continue;
+ }
+
+ size_t cidx = pngle->scanline_ringbuf_cidx;
+ size_t bidx = (pngle->scanline_ringbuf_cidx + bytes_per_pixel) % pngle->scanline_ringbuf_size;
+ size_t aidx = (pngle->scanline_ringbuf_cidx + pngle->scanline_ringbuf_size - bytes_per_pixel) % pngle->scanline_ringbuf_size;
+ // debug_printf("[pngle] cidx = %zd, bidx = %zd, aidx = %zd\n", cidx, bidx, aidx);
+
+ uint8_t c = pngle->scanline_ringbuf[cidx]; // left-up
+ uint8_t b = pngle->scanline_ringbuf[bidx]; // up
+ uint8_t a = pngle->scanline_ringbuf[aidx]; // left
+ uint8_t x = *p++; // target
+ // debug_printf("[pngle] c = 0x%02x, b = 0x%02x, a = 0x%02x, x = 0x%02x\n", c, b, a, x);
+
+ // Reverse the filter
+ switch (pngle->filter_type) {
+ case 0: break; // None
+ case 1: x += a; break; // Sub
+ case 2: x += b; break; // Up
+ case 3: x += (a + b) / 2; break; // Average
+ case 4: x += paeth(a, b, c); break; // Paeth
+ }
+
+ scanline_ringbuf_push(pngle, x); // updates scanline_ringbuf_cidx
+
+ if (pngle->scanline_remain_bytes_to_render < 0) pngle->scanline_remain_bytes_to_render = bytes_per_pixel;
+ if (--pngle->scanline_remain_bytes_to_render == 0) {
+ size_t xidx = (pngle->scanline_ringbuf_cidx + pngle->scanline_ringbuf_size - bytes_per_pixel) % pngle->scanline_ringbuf_size;
+
+ if (pngle_draw_pixels(pngle, xidx) < 0) return -1;
+
+ pngle->scanline_remain_bytes_to_render = -1; // reset
+ }
+ }
+
+ return len;
+}
+
+
+static int pngle_handle_chunk(pngle_t *pngle, const uint8_t *buf, size_t len)
+{
+ size_t consume = 0;
+
+ switch (pngle->chunk_type) {
+ case PNGLE_CHUNK_IHDR:
+ // parse IHDR
+ consume = 13;
+ if (len < consume) return 0;
+
+ debug_printf("[pngle] Parse IHDR\n");
+
+ pngle->hdr.width = read_uint32(buf + 0);
+ pngle->hdr.height = read_uint32(buf + 4);
+ pngle->hdr.depth = read_uint8 (buf + 8);
+ pngle->hdr.color_type = read_uint8 (buf + 9);
+ pngle->hdr.compression = read_uint8 (buf + 10);
+ pngle->hdr.filter = read_uint8 (buf + 11);
+ pngle->hdr.interlace = read_uint8 (buf + 12);
+
+
+ debug_printf("[pngle] width : %d\n", pngle->hdr.width );
+ debug_printf("[pngle] height : %d\n", pngle->hdr.height );
+ debug_printf("[pngle] depth : %d\n", pngle->hdr.depth );
+ debug_printf("[pngle] color_type : %d\n", pngle->hdr.color_type );
+ debug_printf("[pngle] compression: %d\n", pngle->hdr.compression);
+ debug_printf("[pngle] filter : %d\n", pngle->hdr.filter );
+ debug_printf("[pngle] interlace : %d\n", pngle->hdr.interlace );
+
+ /*
+ Color Allowed Interpretation channels
+ Type Bit Depths
+
+ 0 1,2,4,8,16 Each pixel is a grayscale sample. 1 channels (Brightness)
+
+ 2 8,16 Each pixel is an R,G,B triple. 3 channels (R, G, B)
+
+ 3 1,2,4,8 Each pixel is a palette index; 1 channels (palette info)
+ a PLTE chunk must appear.
+
+ 4 8,16 Each pixel is a grayscale sample, 2 channels (Brightness, Alpha)
+ followed by an alpha sample.
+
+ 6 8,16 Each pixel is an R,G,B triple, 4 channels (R, G, B, Alpha)
+ followed by an alpha sample.
+ */
+ // 111
+ // ^-- indexed color (palette)
+ // ^--- Color
+ // ^---- Alpha channel
+
+ switch (pngle->hdr.color_type) {
+ case 0: pngle->channels = 1; if (pngle->hdr.depth != 1 && pngle->hdr.depth != 2 && pngle->hdr.depth != 4 && pngle->hdr.depth != 8 && pngle->hdr.depth != 16) return PNGLE_ERROR("Invalid bit depth"); break; // grayscale
+ case 2: pngle->channels = 3; if ( pngle->hdr.depth != 8 && pngle->hdr.depth != 16) return PNGLE_ERROR("Invalid bit depth"); break; // truecolor
+ case 3: pngle->channels = 1; if (pngle->hdr.depth != 1 && pngle->hdr.depth != 2 && pngle->hdr.depth != 4 && pngle->hdr.depth != 8 ) return PNGLE_ERROR("Invalid bit depth"); break; // indexed color
+ case 4: pngle->channels = 2; if ( pngle->hdr.depth != 8 && pngle->hdr.depth != 16) return PNGLE_ERROR("Invalid bit depth"); break; // grayscale + alpha
+ case 6: pngle->channels = 4; if ( pngle->hdr.depth != 8 && pngle->hdr.depth != 16) return PNGLE_ERROR("Invalid bit depth"); break; // truecolor + alpha
+ default:
+ return PNGLE_ERROR("Incorrect IHDR info");
+ }
+
+ if (pngle->hdr.compression != 0) return PNGLE_ERROR("Unsupported compression type in IHDR");
+ if (pngle->hdr.filter != 0) return PNGLE_ERROR("Unsupported filter type in IHDR");
+
+ // interlace
+ if (set_interlace_pass(pngle, pngle->hdr.interlace ? 1 : 0) < 0) return -1;
+
+ // callback
+ if (pngle->init_callback) pngle->init_callback(pngle, pngle->hdr.width, pngle->hdr.height);
+
+ break;
+
+ case PNGLE_CHUNK_IDAT:
+ // parse & decode IDAT chunk
+ if (len < 1) return 0;
+
+ debug_printf("[pngle] Reading IDAT (len %zd / chunk remain %u)\n", len, pngle->chunk_remain);
+
+ size_t in_bytes = len;
+ size_t out_bytes = pngle->avail_out;
+
+ //debug_printf("[pngle] in_bytes %zd, out_bytes %zd, next_out %p\n", in_bytes, out_bytes, pngle->next_out);
+
+ // XXX: tinfl_decompress always requires (next_out - lz_buf + avail_out) == TINFL_LZ_DICT_SIZE
+ tinfl_status status = tinfl_decompress(&pngle->inflator, (const mz_uint8 *)buf, &in_bytes, pngle->lz_buf, (mz_uint8 *)pngle->next_out, &out_bytes, TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_PARSE_ZLIB_HEADER);
+
+ //debug_printf("[pngle] tinfl_decompress\n");
+ //debug_printf("[pngle] => in_bytes %zd, out_bytes %zd, next_out %p, status %d\n", in_bytes, out_bytes, pngle->next_out, status);
+
+ if (status < TINFL_STATUS_DONE) {
+ // Decompression failed.
+ debug_printf("[pngle] tinfl_decompress() failed with status %d!\n", status);
+ return PNGLE_ERROR("Failed to decompress the IDAT stream");
+ }
+
+ pngle->next_out += out_bytes;
+ pngle->avail_out -= out_bytes;
+
+ // debug_printf("[pngle] => avail_out %zd, next_out %p\n", pngle->avail_out, pngle->next_out);
+
+ if (status == TINFL_STATUS_DONE || pngle->avail_out == 0) {
+ // Output buffer is full, or decompression is done, so write buffer to output file.
+ // XXX: This is the only chance to process the buffer.
+ uint8_t *read_ptr = pngle->lz_buf;
+ size_t n = TINFL_LZ_DICT_SIZE - (size_t)pngle->avail_out;
+
+ // pngle_on_data() usually returns n, otherwise -1 on error
+ if (pngle_on_data(pngle, read_ptr, n) < 0) return -1;
+
+ // XXX: tinfl_decompress always requires (next_out - lz_buf + avail_out) == TINFL_LZ_DICT_SIZE
+ pngle->next_out = pngle->lz_buf;
+ pngle->avail_out = TINFL_LZ_DICT_SIZE;
+ }
+
+ consume = in_bytes;
+ break;
+
+ case PNGLE_CHUNK_PLTE:
+ consume = 3;
+ if (len < consume) return 0;
+
+ memcpy(pngle->palette + pngle->n_palettes * 3, buf, 3);
+
+ debug_printf("[pngle] PLTE[%zd]: (%d, %d, %d)\n"
+ , pngle->n_palettes
+ , pngle->palette[pngle->n_palettes * 3 + 0]
+ , pngle->palette[pngle->n_palettes * 3 + 1]
+ , pngle->palette[pngle->n_palettes * 3 + 2]
+ );
+
+ pngle->n_palettes++;
+
+ break;
+
+ case PNGLE_CHUNK_IEND:
+ consume = 0;
+ break;
+
+ case PNGLE_CHUNK_tRNS:
+ switch (pngle->hdr.color_type) {
+ case 3: consume = 1; break;
+ case 0: consume = 2 * 1; break;
+ case 2: consume = 2 * 3; break;
+ default:
+ return PNGLE_ERROR("tRNS chunk is prohibited on the color type");
+ }
+ if (len < consume) return 0;
+
+ memcpy(pngle->trans_palette + pngle->n_trans_palettes, buf, consume);
+
+ pngle->n_trans_palettes++;
+
+ break;
+
+ case PNGLE_CHUNK_gAMA:
+ consume = 4;
+ if (len < consume) return 0;
+
+ if (setup_gamma_table(pngle, read_uint32(buf)) < 0) return -1;
+
+ break;
+
+ default:
+ // unknown chunk
+ consume = len;
+
+ debug_printf("[pngle] Unknown chunk; %zd bytes discarded\n", consume);
+ break;
+ }
+
+ return consume;
+}
+
+static int pngle_feed_internal(pngle_t *pngle, const uint8_t *buf, size_t len)
+{
+ if (!pngle) return -1;
+
+ switch (pngle->state) {
+ case PNGLE_STATE_ERROR:
+ return -1;
+
+ case PNGLE_STATE_EOF:
+ return len;
+
+ case PNGLE_STATE_INITIAL:
+ // find PNG header
+ if (len < sizeof(png_sig)) return 0;
+
+ if (memcmp(png_sig, buf, sizeof(png_sig))) return PNGLE_ERROR("Incorrect PNG signature");
+
+ debug_printf("[pngle] PNG signature found\n");
+
+ pngle->state = PNGLE_STATE_FIND_CHUNK_HEADER;
+ return sizeof(png_sig);
+
+ case PNGLE_STATE_FIND_CHUNK_HEADER:
+ if (len < 8) return 0;
+
+ pngle->chunk_remain = read_uint32(buf);
+ pngle->chunk_type = read_uint32(buf + 4);
+
+ pngle->crc32 = mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)(buf + 4), 4);
+
+ debug_printf("[pngle] Chunk '%.4s' len %u\n", buf + 4, pngle->chunk_remain);
+
+ pngle->state = PNGLE_STATE_HANDLE_CHUNK;
+
+ // initialize & sanity check
+ switch (pngle->chunk_type) {
+ case PNGLE_CHUNK_IHDR:
+ if (pngle->chunk_remain != 13) return PNGLE_ERROR("Invalid IHDR chunk size");
+ if (pngle->channels != 0) return PNGLE_ERROR("Multiple IHDR chunks are not allowed");
+ break;
+
+ case PNGLE_CHUNK_IDAT:
+ if (pngle->chunk_remain <= 0) return PNGLE_ERROR("Invalid IDAT chunk size");
+ if (pngle->channels == 0) return PNGLE_ERROR("No IHDR chunk is found");
+ if (pngle->hdr.color_type == 3 && pngle->palette == NULL) return PNGLE_ERROR("No PLTE chunk is found");
+
+ if (pngle->next_out == NULL) {
+ // Very first IDAT
+ pngle->next_out = pngle->lz_buf;
+ pngle->avail_out = TINFL_LZ_DICT_SIZE;
+ }
+ break;
+
+ case PNGLE_CHUNK_PLTE:
+ if (pngle->chunk_remain <= 0) return PNGLE_ERROR("Invalid PLTE chunk size");
+ if (pngle->channels == 0) return PNGLE_ERROR("No IHDR chunk is found");
+ if (pngle->palette) return PNGLE_ERROR("Too many PLTE chunk");
+
+ switch (pngle->hdr.color_type) {
+ case 3: // indexed color
+ break;
+ case 2: // truecolor
+ case 6: // truecolor + alpha
+ // suggested palettes
+ break;
+ default:
+ return PNGLE_ERROR("PLTE chunk is prohibited on the color type");
+ }
+
+ if (pngle->chunk_remain % 3) return PNGLE_ERROR("Invalid PLTE chunk size");
+ if (pngle->chunk_remain / 3 > MIN(256, (1UL << pngle->hdr.depth))) return PNGLE_ERROR("Too many palettes in PLTE");
+ if ((pngle->palette = PNGLE_CALLOC(pngle->chunk_remain / 3, 3, "palette")) == NULL) return PNGLE_ERROR("Insufficient memory");
+ pngle->n_palettes = 0;
+ break;
+
+ case PNGLE_CHUNK_IEND:
+ if (pngle->next_out == NULL) return PNGLE_ERROR("No IDAT chunk is found");
+ if (pngle->chunk_remain > 0) return PNGLE_ERROR("Invalid IEND chunk size");
+ break;
+
+ case PNGLE_CHUNK_tRNS:
+ if (pngle->chunk_remain <= 0) return PNGLE_ERROR("Invalid tRNS chunk size");
+ if (pngle->channels == 0) return PNGLE_ERROR("No IHDR chunk is found");
+ if (pngle->trans_palette) return PNGLE_ERROR("Too many tRNS chunk");
+
+ switch (pngle->hdr.color_type) {
+ case 3: // indexed color
+ if (pngle->chunk_remain > (1UL << pngle->hdr.depth)) return PNGLE_ERROR("Too many palettes in tRNS");
+ break;
+ case 0: // grayscale
+ if (pngle->chunk_remain != 2) return PNGLE_ERROR("Invalid tRNS chunk size");
+ break;
+ case 2: // truecolor
+ if (pngle->chunk_remain != 6) return PNGLE_ERROR("Invalid tRNS chunk size");
+ break;
+
+ default:
+ return PNGLE_ERROR("tRNS chunk is prohibited on the color type");
+ }
+ if ((pngle->trans_palette = PNGLE_CALLOC(pngle->chunk_remain, 1, "trans palette")) == NULL) return PNGLE_ERROR("Insufficient memory");
+ pngle->n_trans_palettes = 0;
+ break;
+
+ default:
+ break;
+ }
+
+ return 8;
+
+ case PNGLE_STATE_HANDLE_CHUNK:
+ len = MIN(len, pngle->chunk_remain);
+
+ int consumed = pngle_handle_chunk(pngle, buf, len);
+
+ if (consumed > 0) {
+ if (pngle->chunk_remain < (uint32_t)consumed) return PNGLE_ERROR("Chunk data has been consumed too much");
+
+ pngle->chunk_remain -= consumed;
+ pngle->crc32 = mz_crc32(pngle->crc32, (const mz_uint8 *)buf, consumed);
+ }
+ if (pngle->chunk_remain <= 0) pngle->state = PNGLE_STATE_CRC;
+
+ return consumed;
+
+ case PNGLE_STATE_CRC:
+ if (len < 4) return 0;
+
+ uint32_t crc32 = read_uint32(buf);
+
+ if (crc32 != pngle->crc32) {
+ debug_printf("[pngle] CRC: %08x vs %08x => NG\n", crc32, (uint32_t)pngle->crc32);
+ return PNGLE_ERROR("CRC mismatch");
+ }
+
+ debug_printf("[pngle] CRC: %08x vs %08x => OK\n", crc32, (uint32_t)pngle->crc32);
+ pngle->state = PNGLE_STATE_FIND_CHUNK_HEADER;
+
+ // XXX:
+ if (pngle->chunk_type == PNGLE_CHUNK_IEND) {
+ pngle->state = PNGLE_STATE_EOF;
+ if (pngle->done_callback) pngle->done_callback(pngle);
+ debug_printf("[pngle] DONE\n");
+ }
+
+ return 4;
+
+ default:
+ break;
+ }
+
+ return PNGLE_ERROR("Invalid state");
+}
+
+int pngle_feed(pngle_t *pngle, const void *buf, size_t len)
+{
+ size_t pos = 0;
+ pngle_state_t last_state = pngle->state;
+
+ while (pos < len) {
+ int r = pngle_feed_internal(pngle, (const uint8_t *)buf + pos, len - pos);
+ if (r < 0) return r; // error
+
+ if (r == 0 && last_state == pngle->state) break;
+ last_state = pngle->state;
+
+ pos += r;
+ }
+
+ return pos;
+}
+
+void pngle_set_display_gamma(pngle_t *pngle, double display_gamma)
+{
+ if (!pngle) return ;
+#ifndef PNGLE_NO_GAMMA_CORRECTION
+ pngle->display_gamma = display_gamma;
+#else
+ PNGLE_UNUSED(display_gamma);
+#endif
+}
+
+void pngle_set_init_callback(pngle_t *pngle, pngle_init_callback_t callback)
+{
+ if (!pngle) return ;
+ pngle->init_callback = callback;
+}
+
+void pngle_set_draw_callback(pngle_t *pngle, pngle_draw_callback_t callback)
+{
+ if (!pngle) return ;
+ pngle->draw_callback = callback;
+}
+
+void pngle_set_done_callback(pngle_t *pngle, pngle_done_callback_t callback)
+{
+ if (!pngle) return ;
+ pngle->done_callback = callback;
+}
+
+void pngle_set_user_data(pngle_t *pngle, void *user_data)
+{
+ if (!pngle) return ;
+ pngle->user_data = user_data;
+}
+
+void *pngle_get_user_data(pngle_t *pngle)
+{
+ if (!pngle) return NULL;
+ return pngle->user_data;
+}
+
+/* vim: set ts=4 sw=4 noexpandtab: */
diff --git a/main/drivers/st7789/pngle.h b/main/drivers/st7789/pngle.h
new file mode 100644
index 0000000..6bbd776
--- /dev/null
+++ b/main/drivers/st7789/pngle.h
@@ -0,0 +1,189 @@
+/*-
+ * MIT License
+ *
+ * Copyright (c) 2019 kikuchan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __PNGLE_H__
+#define __PNGLE_H__
+
+#include
+#include
+#include "esp32/rom/miniz.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef MIN
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#endif
+
+#ifdef PNGLE_DEBUG
+#define debug_printf(...) fprintf(stderr, __VA_ARGS__)
+#else
+#define debug_printf(...) ((void)0)
+#endif
+
+//#define PNGLE_NO_GAMMA_CORRECTION
+
+#if 0
+typedef struct __attribute__((__packed__)) {
+ uint8_t red;
+ uint8_t green;
+ uint8_t blue;
+} pixel_png;
+#endif
+
+//rgb565 format
+typedef uint16_t pixel_png;
+
+typedef enum {
+ PNGLE_STATE_ERROR = -2,
+ PNGLE_STATE_EOF = -1,
+ PNGLE_STATE_INITIAL = 0,
+
+ PNGLE_STATE_FIND_CHUNK_HEADER,
+ PNGLE_STATE_HANDLE_CHUNK,
+ PNGLE_STATE_CRC,
+} pngle_state_t;
+
+
+typedef enum {
+// Supported chunks
+// Filter chunk names by following command to (re)generate hex constants;
+// % perl -ne 'chomp; s/.*\s*\/\/\s*//; print "\tPNGLE_CHUNK_$_ = 0x" . unpack("H*") . "UL, // $_\n";'
+ PNGLE_CHUNK_IHDR = 0x49484452UL, // IHDR
+ PNGLE_CHUNK_PLTE = 0x504c5445UL, // PLTE
+ PNGLE_CHUNK_IDAT = 0x49444154UL, // IDAT
+ PNGLE_CHUNK_IEND = 0x49454e44UL, // IEND
+ PNGLE_CHUNK_tRNS = 0x74524e53UL, // tRNS
+ PNGLE_CHUNK_gAMA = 0x67414d41UL, // gAMA
+} pngle_chunk_t;
+
+typedef struct _pngle_ihdr_t {
+ uint32_t width;
+ uint32_t height;
+ uint8_t depth;
+ uint8_t color_type;
+ uint8_t compression;
+ uint8_t filter;
+ uint8_t interlace;
+} pngle_ihdr_t;
+
+typedef unsigned int UINT;
+
+typedef struct pngle pngle_t;
+
+typedef void (*pngle_init_callback_t)(pngle_t *pngle, uint32_t w, uint32_t h);
+typedef void (*pngle_draw_callback_t)(pngle_t *pngle, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint8_t rgba[4]);
+typedef void (*pngle_done_callback_t)(pngle_t *pngle);
+
+struct pngle {
+ pngle_ihdr_t hdr;
+
+ uint_fast8_t channels; // 0 indicates IHDR hasn't been processed yet
+
+ // PLTE chunk
+ size_t n_palettes;
+ uint8_t *palette;
+
+ // tRNS chunk
+ size_t n_trans_palettes;
+ uint8_t *trans_palette;
+
+ // parser state (reset on every chunk header)
+ pngle_state_t state;
+ uint32_t chunk_type;
+ uint32_t chunk_remain;
+ mz_ulong crc32;
+
+ // decompression state (reset on IHDR)
+ tinfl_decompressor inflator; // 11000 bytes
+ uint8_t lz_buf[TINFL_LZ_DICT_SIZE]; // 32768 bytes
+ uint8_t *next_out; // NULL indicates IDAT hasn't been processed yet
+ size_t avail_out;
+
+ // scanline decoder (reset on every set_interlace_pass() call)
+ uint8_t *scanline_ringbuf;
+ size_t scanline_ringbuf_size;
+ size_t scanline_ringbuf_cidx;
+ int_fast8_t scanline_remain_bytes_to_render;
+ int_fast8_t filter_type;
+ uint32_t drawing_x;
+ uint32_t drawing_y;
+
+ // interlace
+ uint_fast8_t interlace_pass;
+
+ const char *error;
+
+#ifndef PNGLE_NO_GAMMA_CORRECTION
+ uint8_t *gamma_table;
+ double display_gamma;
+#endif
+
+ pngle_init_callback_t init_callback;
+ pngle_draw_callback_t draw_callback;
+ pngle_done_callback_t done_callback;
+
+ void *user_data;
+ uint16_t screenWidth;
+ uint16_t screenHeight;
+ uint16_t imageWidth;
+ uint16_t imageHeight;
+ pixel_png **pixels;
+ bool reduction;
+ double scale_factor;
+};
+
+
+// ----------------
+// Basic interfaces
+// ----------------
+pngle_t *pngle_new(uint16_t width, uint16_t height);
+void pngle_destroy(pngle_t *pngle, uint16_t width, uint16_t height);
+void pngle_reset(pngle_t *pngle); // clear its internal state (not applied to pngle_set_* functions)
+const char *pngle_error(pngle_t *pngle);
+int pngle_feed(pngle_t *pngle, const void *buf, size_t len); // returns -1: On error, 0: Need more data, n: n bytes eaten
+
+uint32_t pngle_get_width(pngle_t *pngle);
+uint32_t pngle_get_height(pngle_t *pngle);
+
+void pngle_set_init_callback(pngle_t *png, pngle_init_callback_t callback);
+void pngle_set_draw_callback(pngle_t *png, pngle_draw_callback_t callback);
+void pngle_set_done_callback(pngle_t *png, pngle_done_callback_t callback);
+
+void pngle_set_display_gamma(pngle_t *pngle, double display_gamma); // enables gamma correction by specifying display gamma, typically 2.2. No effect when gAMA chunk is missing
+
+void pngle_set_user_data(pngle_t *pngle, void *user_data);
+void *pngle_get_user_data(pngle_t *pngle);
+
+
+// Get IHDR information
+pngle_ihdr_t *pngle_get_ihdr(pngle_t *pngle);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __PNGLE_H__ */
diff --git a/main/drivers/st7789/st7789.c b/main/drivers/st7789/st7789.c
new file mode 100644
index 0000000..c5cad27
--- /dev/null
+++ b/main/drivers/st7789/st7789.c
@@ -0,0 +1,1111 @@
+#include
+#include
+
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+
+#include
+#include
+#include "esp_log.h"
+
+#include "st7789.h"
+
+#define TAG "ST7789"
+#define _DEBUG_ 0
+
+#if 0
+#ifdef CONFIG_IDF_TARGET_ESP32
+#define LCD_HOST HSPI_HOST
+#elif defined CONFIG_IDF_TARGET_ESP32S2
+#define LCD_HOST SPI2_HOST
+#elif defined CONFIG_IDF_TARGET_ESP32S3
+#define LCD_HOST SPI2_HOST
+#elif defined CONFIG_IDF_TARGET_ESP32C3
+#define LCD_HOST SPI2_HOST
+#endif
+#endif
+
+#if CONFIG_SPI2_HOST
+#define HOST_ID SPI2_HOST
+#elif CONFIG_SPI3_HOST
+#define HOST_ID SPI3_HOST
+#endif
+
+static const int SPI_Command_Mode = 0;
+static const int SPI_Data_Mode = 1;
+// static const int SPI_Frequency = SPI_MASTER_FREQ_8M;
+//static const int SPI_Frequency = SPI_MASTER_FREQ_26M;
+// static const int SPI_Frequency = SPI_MASTER_FREQ_40M;
+static const int SPI_Frequency = SPI_MASTER_FREQ_80M;
+
+
+void spi_master_init(TFT_t * dev, int16_t GPIO_MOSI, int16_t GPIO_SCLK, int16_t GPIO_CS, int16_t GPIO_DC, int16_t GPIO_RESET, int16_t GPIO_BL)
+{
+ esp_err_t ret;
+ gpio_config_t io_conf = {};
+
+ ESP_LOGI(TAG, "GPIO_CS=%d",GPIO_CS);
+ if ( GPIO_CS >= 0 ) {
+ //gpio_pad_select_gpio( GPIO_CS );
+ // gpio_reset_pin( GPIO_CS );
+ // gpio_set_direction( GPIO_CS, GPIO_MODE_OUTPUT );
+ // gpio_set_level( GPIO_CS, 0 );
+
+ //disable interrupt
+ io_conf.intr_type = GPIO_INTR_DISABLE;
+ //set as output mode
+ io_conf.mode = GPIO_MODE_OUTPUT;
+ //bit mask of the pins that you want to set,e.g.GPIO18/19
+ io_conf.pin_bit_mask = (1ULL<= 0 ) {
+ //gpio_pad_select_gpio( GPIO_RESET );
+ gpio_reset_pin( GPIO_RESET );
+ gpio_set_direction( GPIO_RESET, GPIO_MODE_OUTPUT );
+ gpio_set_level( GPIO_RESET, 1 );
+ delayMS(50);
+ gpio_set_level( GPIO_RESET, 0 );
+ delayMS(50);
+ gpio_set_level( GPIO_RESET, 1 );
+ delayMS(50);
+ }
+
+ ESP_LOGI(TAG, "GPIO_BL=%d",GPIO_BL);
+ if ( GPIO_BL >= 0 ) {
+ //gpio_pad_select_gpio(GPIO_BL);
+ // gpio_reset_pin(GPIO_BL);
+ // gpio_set_direction( GPIO_BL, GPIO_MODE_OUTPUT );
+ // gpio_set_level( GPIO_BL, 0 );
+ //disable interrupt
+ io_conf.intr_type = GPIO_INTR_DISABLE;
+ //set as output mode
+ io_conf.mode = GPIO_MODE_OUTPUT;
+ //bit mask of the pins that you want to set,e.g.GPIO18/19
+ io_conf.pin_bit_mask = (1ULL<= 0 ) {
+ devcfg.spics_io_num = GPIO_CS;
+ } else {
+ devcfg.spics_io_num = -1;
+ }
+
+ static spi_device_handle_t handle;
+ ret = spi_bus_add_device( HOST_ID, &devcfg, &handle);
+ printf("spi_bus_add_device = %d\r\n", ret);
+ ESP_LOGD(TAG, "spi_bus_add_device=%d",ret);
+ assert(ret==ESP_OK);
+ dev->_dc = GPIO_DC;
+ dev->_bl = GPIO_BL;
+ dev->_SPIHandle = handle;
+}
+
+
+bool spi_master_write_byte(spi_device_handle_t SPIHandle, const uint8_t* Data, size_t DataLength)
+{
+ spi_transaction_t SPITransaction;
+ esp_err_t ret;
+
+ if ( DataLength > 0 ) {
+ memset( &SPITransaction, 0, sizeof( spi_transaction_t ) );
+ SPITransaction.length = DataLength * 8;
+ SPITransaction.tx_buffer = Data;
+#if 1
+ ret = spi_device_transmit( SPIHandle, &SPITransaction );
+#else
+ ret = spi_device_polling_transmit( SPIHandle, &SPITransaction );
+#endif
+ assert(ret==ESP_OK);
+ }
+
+ return true;
+}
+
+bool spi_master_write_command(TFT_t * dev, uint8_t cmd)
+{
+ static uint8_t Byte = 0;
+ Byte = cmd;
+ gpio_set_level( dev->_dc, SPI_Command_Mode );
+ return spi_master_write_byte( dev->_SPIHandle, &Byte, 1 );
+}
+
+bool spi_master_write_data_byte(TFT_t * dev, uint8_t data)
+{
+ static uint8_t Byte = 0;
+ Byte = data;
+ gpio_set_level( dev->_dc, SPI_Data_Mode );
+ return spi_master_write_byte( dev->_SPIHandle, &Byte, 1 );
+}
+
+
+bool spi_master_write_data_word(TFT_t * dev, uint16_t data)
+{
+ static uint8_t Byte[2];
+ Byte[0] = (data >> 8) & 0xFF;
+ Byte[1] = data & 0xFF;
+ gpio_set_level( dev->_dc, SPI_Data_Mode );
+ return spi_master_write_byte( dev->_SPIHandle, Byte, 2);
+}
+
+bool spi_master_write_addr(TFT_t * dev, uint16_t addr1, uint16_t addr2)
+{
+ static uint8_t Byte[4];
+ Byte[0] = (addr1 >> 8) & 0xFF;
+ Byte[1] = addr1 & 0xFF;
+ Byte[2] = (addr2 >> 8) & 0xFF;
+ Byte[3] = addr2 & 0xFF;
+ gpio_set_level( dev->_dc, SPI_Data_Mode );
+ return spi_master_write_byte( dev->_SPIHandle, Byte, 4);
+}
+
+bool spi_master_write_color(TFT_t * dev, uint16_t color, uint16_t size)
+{
+ static uint8_t Byte[1024];
+ int index = 0;
+ for(int i=0;i> 8) & 0xFF;
+ Byte[index++] = color & 0xFF;
+ }
+ gpio_set_level( dev->_dc, SPI_Data_Mode );
+ return spi_master_write_byte( dev->_SPIHandle, Byte, size*2);
+}
+
+// Add 202001
+bool spi_master_write_colors(TFT_t * dev, uint16_t * colors, uint16_t size)
+{
+ static uint8_t Byte[1024];
+ int index = 0;
+ for(int i=0;i> 8) & 0xFF;
+ Byte[index++] = colors[i] & 0xFF;
+ }
+ gpio_set_level( dev->_dc, SPI_Data_Mode );
+ return spi_master_write_byte( dev->_SPIHandle, Byte, size*2);
+}
+
+void delayMS(int ms) {
+ int _ms = ms + (portTICK_PERIOD_MS - 1);
+ TickType_t xTicksToDelay = _ms / portTICK_PERIOD_MS;
+ ESP_LOGD(TAG, "ms=%d _ms=%d portTICK_PERIOD_MS=%d xTicksToDelay=%d",ms,_ms,portTICK_PERIOD_MS,xTicksToDelay);
+ vTaskDelay(xTicksToDelay);
+}
+
+
+void lcdInit(TFT_t * dev, int width, int height, int offsetx, int offsety)
+{
+ dev->_width = width;
+ dev->_height = height;
+ dev->_offsetx = offsetx;
+ dev->_offsety = offsety;
+ dev->_font_direction = DIRECTION0;
+ dev->_font_fill = false;
+ dev->_font_underline = false;
+
+#if 1
+ spi_master_write_command(dev, 0x01); //Software Reset
+ delayMS(150);
+
+ spi_master_write_command(dev, 0x11); //Sleep Out
+ delayMS(255);
+
+ spi_master_write_command(dev, 0x3A); //Interface Pixel Format
+ spi_master_write_data_byte(dev, 0x55);
+ delayMS(10);
+
+ spi_master_write_command(dev, 0x36); //Memory Data Access Control
+ spi_master_write_data_byte(dev, 0x00);
+
+ // spi_master_write_command(dev, 0x2A); //Column Address Set
+ // spi_master_write_data_byte(dev, 0x00);
+ // spi_master_write_data_byte(dev, 0x00);
+ // spi_master_write_data_byte(dev, 0x00);
+ // spi_master_write_data_byte(dev, 0xF0);
+
+ // spi_master_write_command(dev, 0x2B); //Row Address Set
+ // spi_master_write_data_byte(dev, 0x00);
+ // spi_master_write_data_byte(dev, 0x00);
+ // spi_master_write_data_byte(dev, 0x00);
+ // spi_master_write_data_byte(dev, 0xF0);
+
+ spi_master_write_command(dev, 0x2A); //Column Address Set
+ spi_master_write_data_byte(dev, 0x00);
+ spi_master_write_data_byte(dev, 0x00); //0
+ spi_master_write_data_byte(dev, 0x00);
+ spi_master_write_data_byte(dev, 0xEF); //239
+
+ spi_master_write_command(dev, 0x2B); //Row Address Set
+ spi_master_write_data_byte(dev, 0x00);
+ spi_master_write_data_byte(dev, 0x14); //0
+ spi_master_write_data_byte(dev, 0x01);
+ spi_master_write_data_byte(dev, 0x2B);
+
+ spi_master_write_command(dev, 0x21); //Display Inversion On
+ delayMS(10);
+
+ spi_master_write_command(dev, 0x13); //Normal Display Mode On
+ delayMS(10);
+
+ spi_master_write_command(dev, 0x29); //Display ON
+ delayMS(255);
+
+
+#else
+ spi_master_write_command(dev, 0x01);
+
+ delayMS(120);
+
+ spi_master_write_command(dev, 0x11);
+
+ delayMS(120);
+
+ spi_master_write_command(dev, 0x36);
+ spi_master_write_data_byte(dev, 0x00);
+
+ spi_master_write_command(dev, 0x3A);
+ spi_master_write_data_byte(dev, 0x06);
+
+ spi_master_write_command(dev, 0xB2);
+ spi_master_write_data_byte(dev, 0x0B);
+ spi_master_write_data_byte(dev, 0x0B);
+ spi_master_write_data_byte(dev, 0x00);
+ spi_master_write_data_byte(dev, 0x33);
+ spi_master_write_data_byte(dev, 0x33);
+
+ spi_master_write_command(dev, 0xB7);
+ spi_master_write_data_byte(dev, 0x11);
+
+ spi_master_write_command(dev, 0xBB);
+ spi_master_write_data_byte(dev, 0x2F);
+
+ spi_master_write_command(dev, 0xC0);
+ spi_master_write_data_byte(dev, 0x2C);
+
+ spi_master_write_command(dev, 0xC2);
+ spi_master_write_data_byte(dev, 0x01);
+
+ spi_master_write_command(dev, 0xC3);
+ spi_master_write_data_byte(dev, 0x0D);
+
+ spi_master_write_command(dev, 0xC4);
+ spi_master_write_data_byte(dev, 0x20); //VDV, 0x20:0v
+
+ spi_master_write_command(dev, 0xC6);
+ spi_master_write_data_byte(dev, 0x13); //0x13:60Hz
+
+ spi_master_write_command(dev, 0xD0);
+ spi_master_write_data_byte(dev, 0xA4);
+ spi_master_write_data_byte(dev, 0xA1);
+
+ spi_master_write_command(dev, 0xD6);
+ spi_master_write_data_byte(dev, 0xA1); //sleep in后,gate输出为GND
+
+ spi_master_write_command(dev, 0xE0);
+ spi_master_write_data_byte(dev, 0xF0);
+ spi_master_write_data_byte(dev, 0x04);
+ spi_master_write_data_byte(dev, 0x07);
+ spi_master_write_data_byte(dev, 0x09);
+ spi_master_write_data_byte(dev, 0x07);
+ spi_master_write_data_byte(dev, 0x13);
+ spi_master_write_data_byte(dev, 0x25);
+ spi_master_write_data_byte(dev, 0x33);
+ spi_master_write_data_byte(dev, 0x3C);
+ spi_master_write_data_byte(dev, 0x34);
+ spi_master_write_data_byte(dev, 0x10);
+ spi_master_write_data_byte(dev, 0x10);
+ spi_master_write_data_byte(dev, 0x29);
+ spi_master_write_data_byte(dev, 0x32);
+
+ spi_master_write_command(dev, 0xE1);
+ spi_master_write_data_byte(dev, 0xF0);
+ spi_master_write_data_byte(dev, 0x05);
+ spi_master_write_data_byte(dev, 0x08);
+ spi_master_write_data_byte(dev, 0x0A);
+ spi_master_write_data_byte(dev, 0x09);
+ spi_master_write_data_byte(dev, 0x05);
+ spi_master_write_data_byte(dev, 0x25);
+ spi_master_write_data_byte(dev, 0x32);
+ spi_master_write_data_byte(dev, 0x3B);
+ spi_master_write_data_byte(dev, 0x3B);
+ spi_master_write_data_byte(dev, 0x17);
+ spi_master_write_data_byte(dev, 0x18);
+ spi_master_write_data_byte(dev, 0x2E);
+ spi_master_write_data_byte(dev, 0x37);
+
+ spi_master_write_command(dev, 0xE4);
+ spi_master_write_data_byte(dev, 0x25); //使用240根gate (N+1)*8
+ spi_master_write_data_byte(dev, 0x00); //设定gate起点位置
+ spi_master_write_data_byte(dev, 0x00); //当gate没有用完时,bit4(TMG)设为0
+
+ // spi_master_write_command(dev, 0x21);
+
+ spi_master_write_command(dev, 0x29);
+
+ spi_master_write_command(dev, 0x2A); //Column Address Set
+ spi_master_write_data_byte(dev, 0x00);
+ spi_master_write_data_byte(dev, 0x00); //0
+ spi_master_write_data_byte(dev, 0x00);
+ spi_master_write_data_byte(dev, 0xEF); //239
+
+ spi_master_write_command(dev, 0x2B); //Row Address Set
+ spi_master_write_data_byte(dev, 0x00);
+ spi_master_write_data_byte(dev, 0x14); //0
+ spi_master_write_data_byte(dev, 0x01);
+ spi_master_write_data_byte(dev, 0x2B);
+
+ spi_master_write_command(dev, 0x2C);
+#endif
+
+ if(dev->_bl >= 0) {
+ gpio_set_level( dev->_bl, 0 );
+ }
+}
+
+
+// Draw pixel
+// x:X coordinate
+// y:Y coordinate
+// color:color
+void lcdDrawPixel(TFT_t * dev, uint16_t x, uint16_t y, uint16_t color){
+ if (x >= dev->_width) return;
+ if (y >= dev->_height) return;
+
+ uint16_t _x = x + dev->_offsetx;
+ uint16_t _y = y + dev->_offsety;
+
+ spi_master_write_command(dev, 0x2A); // set column(x) address
+ spi_master_write_addr(dev, _x, _x);
+ spi_master_write_command(dev, 0x2B); // set Page(y) address
+ spi_master_write_addr(dev, _y, _y);
+ spi_master_write_command(dev, 0x2C); // Memory Write
+ spi_master_write_data_word(dev, color);
+}
+
+
+// Draw multi pixel
+// x:X coordinate
+// y:Y coordinate
+// size:Number of colors
+// colors:colors
+void lcdDrawMultiPixels(TFT_t * dev, uint16_t x, uint16_t y, uint16_t size, uint16_t * colors) {
+ if (x+size > dev->_width) return;
+ if (y >= dev->_height) return;
+
+ uint16_t _x1 = x + dev->_offsetx;
+ uint16_t _x2 = _x1 + size;
+ uint16_t _y1 = y + dev->_offsety;
+ uint16_t _y2 = _y1;
+
+ spi_master_write_command(dev, 0x2A); // set column(x) address
+ spi_master_write_addr(dev, _x1, _x2);
+ spi_master_write_command(dev, 0x2B); // set Page(y) address
+ spi_master_write_addr(dev, _y1, _y2);
+ spi_master_write_command(dev, 0x2C); // Memory Write
+ spi_master_write_colors(dev, colors, size);
+}
+
+// Draw rectangle of filling
+// x1:Start X coordinate
+// y1:Start Y coordinate
+// x2:End X coordinate
+// y2:End Y coordinate
+// color:color
+void lcdDrawFillRect(TFT_t * dev, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color) {
+ if (x1 >= dev->_width) return;
+ if (x2 >= dev->_width) x2=dev->_width-1;
+ if (y1 >= dev->_height) return;
+ if (y2 >= dev->_height) y2=dev->_height-1;
+
+ ESP_LOGD(TAG,"offset(x)=%d offset(y)=%d",dev->_offsetx,dev->_offsety);
+ uint16_t _x1 = x1 + dev->_offsetx;
+ uint16_t _x2 = x2 + dev->_offsetx;
+ uint16_t _y1 = y1 + dev->_offsety;
+ uint16_t _y2 = y2 + dev->_offsety;
+
+ bool ret = spi_master_write_command(dev, 0x2A); // set column(x) address
+ printf("ret = %d\r\n", ret);
+ spi_master_write_addr(dev, _x1, _x2);
+ spi_master_write_command(dev, 0x2B); // set Page(y) address
+ spi_master_write_addr(dev, _y1, _y2);
+ spi_master_write_command(dev, 0x2C); // Memory Write
+ for(int i=_x1;i<=_x2;i++){
+ uint16_t size = _y2-_y1+1;
+ spi_master_write_color(dev, color, size);
+#if 0
+ for(j=y1;j<=y2;j++){
+ //ESP_LOGD(TAG,"i=%d j=%d",i,j);
+ spi_master_write_data_word(dev, color);
+ }
+#endif
+ }
+}
+
+// Display OFF
+void lcdDisplayOff(TFT_t * dev) {
+ spi_master_write_command(dev, 0x28); //Display off
+}
+
+// Display ON
+void lcdDisplayOn(TFT_t * dev) {
+ spi_master_write_command(dev, 0x29); //Display on
+}
+
+// Fill screen
+// color:color
+void lcdFillScreen(TFT_t * dev, uint16_t color) {
+ lcdDrawFillRect(dev, 0, 0, dev->_width-1, dev->_height-1, color);
+}
+
+// Draw line
+// x1:Start X coordinate
+// y1:Start Y coordinate
+// x2:End X coordinate
+// y2:End Y coordinate
+// color:color
+void lcdDrawLine(TFT_t * dev, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color) {
+ int i;
+ int dx,dy;
+ int sx,sy;
+ int E;
+
+ /* distance between two points */
+ dx = ( x2 > x1 ) ? x2 - x1 : x1 - x2;
+ dy = ( y2 > y1 ) ? y2 - y1 : y1 - y2;
+
+ /* direction of two point */
+ sx = ( x2 > x1 ) ? 1 : -1;
+ sy = ( y2 > y1 ) ? 1 : -1;
+
+ /* inclination < 1 */
+ if ( dx > dy ) {
+ E = -dx;
+ for ( i = 0 ; i <= dx ; i++ ) {
+ lcdDrawPixel(dev, x1, y1, color);
+ x1 += sx;
+ E += 2 * dy;
+ if ( E >= 0 ) {
+ y1 += sy;
+ E -= 2 * dx;
+ }
+ }
+
+ /* inclination >= 1 */
+ } else {
+ E = -dy;
+ for ( i = 0 ; i <= dy ; i++ ) {
+ lcdDrawPixel(dev, x1, y1, color);
+ y1 += sy;
+ E += 2 * dx;
+ if ( E >= 0 ) {
+ x1 += sx;
+ E -= 2 * dy;
+ }
+ }
+ }
+}
+
+// Draw rectangle
+// x1:Start X coordinate
+// y1:Start Y coordinate
+// x2:End X coordinate
+// y2:End Y coordinate
+// color:color
+void lcdDrawRect(TFT_t * dev, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color) {
+ lcdDrawLine(dev, x1, y1, x2, y1, color);
+ lcdDrawLine(dev, x2, y1, x2, y2, color);
+ lcdDrawLine(dev, x2, y2, x1, y2, color);
+ lcdDrawLine(dev, x1, y2, x1, y1, color);
+}
+
+// Draw rectangle with angle
+// xc:Center X coordinate
+// yc:Center Y coordinate
+// w:Width of rectangle
+// h:Height of rectangle
+// angle :Angle of rectangle
+// color :color
+
+//When the origin is (0, 0), the point (x1, y1) after rotating the point (x, y) by the angle is obtained by the following calculation.
+// x1 = x * cos(angle) - y * sin(angle)
+// y1 = x * sin(angle) + y * cos(angle)
+void lcdDrawRectAngle(TFT_t * dev, uint16_t xc, uint16_t yc, uint16_t w, uint16_t h, uint16_t angle, uint16_t color) {
+ double xd,yd,rd;
+ int x1,y1;
+ int x2,y2;
+ int x3,y3;
+ int x4,y4;
+ rd = -angle * M_PI / 180.0;
+ xd = 0.0 - w/2;
+ yd = h/2;
+ x1 = (int)(xd * cos(rd) - yd * sin(rd) + xc);
+ y1 = (int)(xd * sin(rd) + yd * cos(rd) + yc);
+
+ yd = 0.0 - yd;
+ x2 = (int)(xd * cos(rd) - yd * sin(rd) + xc);
+ y2 = (int)(xd * sin(rd) + yd * cos(rd) + yc);
+
+ xd = w/2;
+ yd = h/2;
+ x3 = (int)(xd * cos(rd) - yd * sin(rd) + xc);
+ y3 = (int)(xd * sin(rd) + yd * cos(rd) + yc);
+
+ yd = 0.0 - yd;
+ x4 = (int)(xd * cos(rd) - yd * sin(rd) + xc);
+ y4 = (int)(xd * sin(rd) + yd * cos(rd) + yc);
+
+ lcdDrawLine(dev, x1, y1, x2, y2, color);
+ lcdDrawLine(dev, x1, y1, x3, y3, color);
+ lcdDrawLine(dev, x2, y2, x4, y4, color);
+ lcdDrawLine(dev, x3, y3, x4, y4, color);
+}
+
+// Draw triangle
+// xc:Center X coordinate
+// yc:Center Y coordinate
+// w:Width of triangle
+// h:Height of triangle
+// angle :Angle of triangle
+// color :color
+
+//When the origin is (0, 0), the point (x1, y1) after rotating the point (x, y) by the angle is obtained by the following calculation.
+// x1 = x * cos(angle) - y * sin(angle)
+// y1 = x * sin(angle) + y * cos(angle)
+void lcdDrawTriangle(TFT_t * dev, uint16_t xc, uint16_t yc, uint16_t w, uint16_t h, uint16_t angle, uint16_t color) {
+ double xd,yd,rd;
+ int x1,y1;
+ int x2,y2;
+ int x3,y3;
+ rd = -angle * M_PI / 180.0;
+ xd = 0.0;
+ yd = h/2;
+ x1 = (int)(xd * cos(rd) - yd * sin(rd) + xc);
+ y1 = (int)(xd * sin(rd) + yd * cos(rd) + yc);
+
+ xd = w/2;
+ yd = 0.0 - yd;
+ x2 = (int)(xd * cos(rd) - yd * sin(rd) + xc);
+ y2 = (int)(xd * sin(rd) + yd * cos(rd) + yc);
+
+ xd = 0.0 - w/2;
+ x3 = (int)(xd * cos(rd) - yd * sin(rd) + xc);
+ y3 = (int)(xd * sin(rd) + yd * cos(rd) + yc);
+
+ lcdDrawLine(dev, x1, y1, x2, y2, color);
+ lcdDrawLine(dev, x1, y1, x3, y3, color);
+ lcdDrawLine(dev, x2, y2, x3, y3, color);
+}
+
+// Draw circle
+// x0:Central X coordinate
+// y0:Central Y coordinate
+// r:radius
+// color:color
+void lcdDrawCircle(TFT_t * dev, uint16_t x0, uint16_t y0, uint16_t r, uint16_t color) {
+ int x;
+ int y;
+ int err;
+ int old_err;
+
+ x=0;
+ y=-r;
+ err=2-2*r;
+ do{
+ lcdDrawPixel(dev, x0-x, y0+y, color);
+ lcdDrawPixel(dev, x0-y, y0-x, color);
+ lcdDrawPixel(dev, x0+x, y0-y, color);
+ lcdDrawPixel(dev, x0+y, y0+x, color);
+ if ((old_err=err)<=x) err+=++x*2+1;
+ if (old_err>y || err>x) err+=++y*2+1;
+ } while(y<0);
+}
+
+// Draw circle of filling
+// x0:Central X coordinate
+// y0:Central Y coordinate
+// r:radius
+// color:color
+void lcdDrawFillCircle(TFT_t * dev, uint16_t x0, uint16_t y0, uint16_t r, uint16_t color) {
+ int x;
+ int y;
+ int err;
+ int old_err;
+ int ChangeX;
+
+ x=0;
+ y=-r;
+ err=2-2*r;
+ ChangeX=1;
+ do{
+ if(ChangeX) {
+ lcdDrawLine(dev, x0-x, y0-y, x0-x, y0+y, color);
+ lcdDrawLine(dev, x0+x, y0-y, x0+x, y0+y, color);
+ } // endif
+ ChangeX=(old_err=err)<=x;
+ if (ChangeX) err+=++x*2+1;
+ if (old_err>y || err>x) err+=++y*2+1;
+ } while(y<=0);
+}
+
+// Draw rectangle with round corner
+// x1:Start X coordinate
+// y1:Start Y coordinate
+// x2:End X coordinate
+// y2:End Y coordinate
+// r:radius
+// color:color
+void lcdDrawRoundRect(TFT_t * dev, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t r, uint16_t color) {
+ int x;
+ int y;
+ int err;
+ int old_err;
+ unsigned char temp;
+
+ if(x1>x2) {
+ temp=x1; x1=x2; x2=temp;
+ } // endif
+
+ if(y1>y2) {
+ temp=y1; y1=y2; y2=temp;
+ } // endif
+
+ ESP_LOGD(TAG, "x1=%d x2=%d delta=%d r=%d",x1, x2, x2-x1, r);
+ ESP_LOGD(TAG, "y1=%d y2=%d delta=%d r=%d",y1, y2, y2-y1, r);
+ if (x2-x1 < r) return; // Add 20190517
+ if (y2-y1 < r) return; // Add 20190517
+
+ x=0;
+ y=-r;
+ err=2-2*r;
+
+ do{
+ if(x) {
+ lcdDrawPixel(dev, x1+r-x, y1+r+y, color);
+ lcdDrawPixel(dev, x2-r+x, y1+r+y, color);
+ lcdDrawPixel(dev, x1+r-x, y2-r-y, color);
+ lcdDrawPixel(dev, x2-r+x, y2-r-y, color);
+ } // endif
+ if ((old_err=err)<=x) err+=++x*2+1;
+ if (old_err>y || err>x) err+=++y*2+1;
+ } while(y<0);
+
+ ESP_LOGD(TAG, "x1+r=%d x2-r=%d",x1+r, x2-r);
+ lcdDrawLine(dev, x1+r,y1 ,x2-r,y1 ,color);
+ lcdDrawLine(dev, x1+r,y2 ,x2-r,y2 ,color);
+ ESP_LOGD(TAG, "y1+r=%d y2-r=%d",y1+r, y2-r);
+ lcdDrawLine(dev, x1 ,y1+r,x1 ,y2-r,color);
+ lcdDrawLine(dev, x2 ,y1+r,x2 ,y2-r,color);
+}
+
+// Draw arrow
+// x1:Start X coordinate
+// y1:Start Y coordinate
+// x2:End X coordinate
+// y2:End Y coordinate
+// w:Width of the botom
+// color:color
+// Thanks http://k-hiura.cocolog-nifty.com/blog/2010/11/post-2a62.html
+void lcdDrawArrow(TFT_t * dev, uint16_t x0,uint16_t y0,uint16_t x1,uint16_t y1,uint16_t w,uint16_t color) {
+ double Vx= x1 - x0;
+ double Vy= y1 - y0;
+ double v = sqrt(Vx*Vx+Vy*Vy);
+ // printf("v=%f\n",v);
+ double Ux= Vx/v;
+ double Uy= Vy/v;
+
+ uint16_t L[2],R[2];
+ L[0]= x1 - Uy*w - Ux*v;
+ L[1]= y1 + Ux*w - Uy*v;
+ R[0]= x1 + Uy*w - Ux*v;
+ R[1]= y1 - Ux*w - Uy*v;
+ //printf("L=%d-%d R=%d-%d\n",L[0],L[1],R[0],R[1]);
+
+ //lcdDrawLine(x0,y0,x1,y1,color);
+ lcdDrawLine(dev, x1, y1, L[0], L[1], color);
+ lcdDrawLine(dev, x1, y1, R[0], R[1], color);
+ lcdDrawLine(dev, L[0], L[1], R[0], R[1], color);
+}
+
+
+// Draw arrow of filling
+// x1:Start X coordinate
+// y1:Start Y coordinate
+// x2:End X coordinate
+// y2:End Y coordinate
+// w:Width of the botom
+// color:color
+void lcdDrawFillArrow(TFT_t * dev, uint16_t x0,uint16_t y0,uint16_t x1,uint16_t y1,uint16_t w,uint16_t color) {
+ double Vx= x1 - x0;
+ double Vy= y1 - y0;
+ double v = sqrt(Vx*Vx+Vy*Vy);
+ //printf("v=%f\n",v);
+ double Ux= Vx/v;
+ double Uy= Vy/v;
+
+ uint16_t L[2],R[2];
+ L[0]= x1 - Uy*w - Ux*v;
+ L[1]= y1 + Ux*w - Uy*v;
+ R[0]= x1 + Uy*w - Ux*v;
+ R[1]= y1 - Ux*w - Uy*v;
+ //printf("L=%d-%d R=%d-%d\n",L[0],L[1],R[0],R[1]);
+
+ lcdDrawLine(dev, x0, y0, x1, y1, color);
+ lcdDrawLine(dev, x1, y1, L[0], L[1], color);
+ lcdDrawLine(dev, x1, y1, R[0], R[1], color);
+ lcdDrawLine(dev, L[0], L[1], R[0], R[1], color);
+
+ int ww;
+ for(ww=w-1;ww>0;ww--) {
+ L[0]= x1 - Uy*ww - Ux*v;
+ L[1]= y1 + Ux*ww - Uy*v;
+ R[0]= x1 + Uy*ww - Ux*v;
+ R[1]= y1 - Ux*ww - Uy*v;
+ //printf("Fill>L=%d-%d R=%d-%d\n",L[0],L[1],R[0],R[1]);
+ lcdDrawLine(dev, x1, y1, L[0], L[1], color);
+ lcdDrawLine(dev, x1, y1, R[0], R[1], color);
+ }
+}
+
+
+// RGB565 conversion
+// RGB565 is R(5)+G(6)+B(5)=16bit color format.
+// Bit image "RRRRRGGGGGGBBBBB"
+uint16_t rgb565_conv(uint16_t r,uint16_t g,uint16_t b) {
+ return (((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3));
+}
+
+// Draw ASCII character
+// x:X coordinate
+// y:Y coordinate
+// ascii: ascii code
+// color:color
+int lcdDrawChar(TFT_t * dev, FontxFile *fxs, uint16_t x, uint16_t y, uint8_t ascii, uint16_t color) {
+ uint16_t xx,yy,bit,ofs;
+ unsigned char fonts[128]; // font pattern
+ unsigned char pw, ph;
+ int h,w;
+ uint16_t mask;
+ bool rc;
+
+ if(_DEBUG_)printf("_font_direction=%d\n",dev->_font_direction);
+ rc = GetFontx(fxs, ascii, fonts, &pw, &ph);
+ if(_DEBUG_)printf("GetFontx rc=%d pw=%d ph=%d\n",rc,pw,ph);
+ if (!rc) return 0;
+
+ int16_t xd1 = 0;
+ int16_t yd1 = 0;
+ int16_t xd2 = 0;
+ int16_t yd2 = 0;
+ uint16_t xss = 0;
+ uint16_t yss = 0;
+ int16_t xsd = 0;
+ int16_t ysd = 0;
+ int16_t next = 0;
+ uint16_t x0 = 0;
+ uint16_t x1 = 0;
+ uint16_t y0 = 0;
+ uint16_t y1 = 0;
+ if (dev->_font_direction == 0) {
+ xd1 = +1;
+ yd1 = +1; //-1;
+ xd2 = 0;
+ yd2 = 0;
+ xss = x;
+ yss = y - (ph - 1);
+ xsd = 1;
+ ysd = 0;
+ next = x + pw;
+
+ x0 = x;
+ y0 = y - (ph-1);
+ x1 = x + (pw-1);
+ y1 = y;
+ } else if (dev->_font_direction == 2) {
+ xd1 = -1;
+ yd1 = -1; //+1;
+ xd2 = 0;
+ yd2 = 0;
+ xss = x;
+ yss = y + ph + 1;
+ xsd = 1;
+ ysd = 0;
+ next = x - pw;
+
+ x0 = x - (pw-1);
+ y0 = y;
+ x1 = x;
+ y1 = y + (ph-1);
+ } else if (dev->_font_direction == 1) {
+ xd1 = 0;
+ yd1 = 0;
+ xd2 = -1;
+ yd2 = +1; //-1;
+ xss = x + ph;
+ yss = y;
+ xsd = 0;
+ ysd = 1;
+ next = y + pw; //y - pw;
+
+ x0 = x;
+ y0 = y;
+ x1 = x + (ph-1);
+ y1 = y + (pw-1);
+ } else if (dev->_font_direction == 3) {
+ xd1 = 0;
+ yd1 = 0;
+ xd2 = +1;
+ yd2 = -1; //+1;
+ xss = x - (ph - 1);
+ yss = y;
+ xsd = 0;
+ ysd = 1;
+ next = y - pw; //y + pw;
+
+ x0 = x - (ph-1);
+ y0 = y - (pw-1);
+ x1 = x;
+ y1 = y;
+ }
+
+ if (dev->_font_fill) lcdDrawFillRect(dev, x0, y0, x1, y1, dev->_font_fill_color);
+
+ int bits;
+ if(_DEBUG_)printf("xss=%d yss=%d\n",xss,yss);
+ ofs = 0;
+ yy = yss;
+ xx = xss;
+ for(h=0;h_font_fill) lcdDrawPixel(dev, xx, yy, dev->_font_fill_color);
+ }
+ if (h == (ph-2) && dev->_font_underline)
+ lcdDrawPixel(dev, xx, yy, dev->_font_underline_color);
+ if (h == (ph-1) && dev->_font_underline)
+ lcdDrawPixel(dev, xx, yy, dev->_font_underline_color);
+ xx = xx + xd1;
+ yy = yy + yd2;
+ mask = mask >> 1;
+ }
+ ofs++;
+ }
+ yy = yy + yd1;
+ xx = xx + xd2;
+ }
+
+ if (next < 0) next = 0;
+ return next;
+}
+
+int lcdDrawString(TFT_t * dev, FontxFile *fx, uint16_t x, uint16_t y, uint8_t * ascii, uint16_t color) {
+ int length = strlen((char *)ascii);
+ if(_DEBUG_)printf("lcdDrawString length=%d\n",length);
+ for(int i=0;i_font_direction == 0)
+ x = lcdDrawChar(dev, fx, x, y, ascii[i], color);
+ if (dev->_font_direction == 1)
+ y = lcdDrawChar(dev, fx, x, y, ascii[i], color);
+ if (dev->_font_direction == 2)
+ x = lcdDrawChar(dev, fx, x, y, ascii[i], color);
+ if (dev->_font_direction == 3)
+ y = lcdDrawChar(dev, fx, x, y, ascii[i], color);
+ }
+ if (dev->_font_direction == 0) return x;
+ if (dev->_font_direction == 2) return x;
+ if (dev->_font_direction == 1) return y;
+ if (dev->_font_direction == 3) return y;
+ return 0;
+}
+
+
+// Draw Non-Alphanumeric character
+// x:X coordinate
+// y:Y coordinate
+// code: charcter code
+// color:color
+int lcdDrawCode(TFT_t * dev, FontxFile *fx, uint16_t x,uint16_t y,uint8_t code,uint16_t color) {
+ if(_DEBUG_)printf("code=%x x=%d y=%d\n",code,x,y);
+ if (dev->_font_direction == 0)
+ x = lcdDrawChar(dev, fx, x, y, code, color);
+ if (dev->_font_direction == 1)
+ y = lcdDrawChar(dev, fx, x, y, code, color);
+ if (dev->_font_direction == 2)
+ x = lcdDrawChar(dev, fx, x, y, code, color);
+ if (dev->_font_direction == 3)
+ y = lcdDrawChar(dev, fx, x, y, code, color);
+ if (dev->_font_direction == 0) return x;
+ if (dev->_font_direction == 2) return x;
+ if (dev->_font_direction == 1) return y;
+ if (dev->_font_direction == 3) return y;
+ return 0;
+}
+
+#if 0
+// Draw UTF8 character
+// x:X coordinate
+// y:Y coordinate
+// utf8: UTF8 code
+// color:color
+int lcdDrawUTF8Char(TFT_t * dev, FontxFile *fx, uint16_t x,uint16_t y,uint8_t *utf8,uint16_t color) {
+ uint16_t sjis[1];
+
+ sjis[0] = UTF2SJIS(utf8);
+ if(_DEBUG_)printf("sjis=%04x\n",sjis[0]);
+ return lcdDrawSJISChar(dev, fx, x, y, sjis[0], color);
+}
+
+// Draw UTF8 string
+// x:X coordinate
+// y:Y coordinate
+// utfs: UTF8 string
+// color:color
+int lcdDrawUTF8String(TFT_t * dev, FontxFile *fx, uint16_t x, uint16_t y, unsigned char *utfs, uint16_t color) {
+
+ int i;
+ int spos;
+ uint16_t sjis[64];
+ spos = String2SJIS(utfs, strlen((char *)utfs), sjis, 64);
+ if(_DEBUG_)printf("spos=%d\n",spos);
+ for(i=0;i_font_direction == 0)
+ x = lcdDrawSJISChar(dev, fx, x, y, sjis[i], color);
+ if (dev->_font_direction == 1)
+ y = lcdDrawSJISChar(dev, fx, x, y, sjis[i], color);
+ if (dev->_font_direction == 2)
+ x = lcdDrawSJISChar(dev, fx, x, y, sjis[i], color);
+ if (dev->_font_direction == 3)
+ y = lcdDrawSJISChar(dev, fx, x, y, sjis[i], color);
+ }
+ if (dev->_font_direction == 0) return x;
+ if (dev->_font_direction == 2) return x;
+ if (dev->_font_direction == 1) return y;
+ if (dev->_font_direction == 3) return y;
+ return 0;
+}
+#endif
+
+// Set font direction
+// dir:Direction
+void lcdSetFontDirection(TFT_t * dev, uint16_t dir) {
+ dev->_font_direction = dir;
+}
+
+// Set font filling
+// color:fill color
+void lcdSetFontFill(TFT_t * dev, uint16_t color) {
+ dev->_font_fill = true;
+ dev->_font_fill_color = color;
+}
+
+// UnSet font filling
+void lcdUnsetFontFill(TFT_t * dev) {
+ dev->_font_fill = false;
+}
+
+// Set font underline
+// color:frame color
+void lcdSetFontUnderLine(TFT_t * dev, uint16_t color) {
+ dev->_font_underline = true;
+ dev->_font_underline_color = color;
+}
+
+// UnSet font underline
+void lcdUnsetFontUnderLine(TFT_t * dev) {
+ dev->_font_underline = false;
+}
+
+// Backlight OFF
+void lcdBacklightOff(TFT_t * dev) {
+ if(dev->_bl >= 0) {
+ gpio_set_level( dev->_bl, 0 );
+ }
+}
+
+// Backlight ON
+void lcdBacklightOn(TFT_t * dev) {
+ if(dev->_bl >= 0) {
+ gpio_set_level( dev->_bl, 1 );
+ }
+}
+
+// Display Inversion Off
+void lcdInversionOff(TFT_t * dev) {
+ spi_master_write_command(dev, 0x20); //Display Inversion Off
+}
+
+// Display Inversion On
+void lcdInversionOn(TFT_t * dev) {
+ spi_master_write_command(dev, 0x21); //Display Inversion On
+}
diff --git a/main/drivers/st7789/st7789.h b/main/drivers/st7789/st7789.h
new file mode 100644
index 0000000..c2c5c1a
--- /dev/null
+++ b/main/drivers/st7789/st7789.h
@@ -0,0 +1,81 @@
+#ifndef MAIN_ST7789_H_
+#define MAIN_ST7789_H_
+
+#include "driver/spi_master.h"
+#include "fontx.h"
+
+#define RED 0xf800
+#define GREEN 0x07e0
+#define BLUE 0x001f
+#define BLACK 0x0000
+#define WHITE 0xffff
+#define GRAY 0x8c51
+#define YELLOW 0xFFE0
+#define CYAN 0x07FF
+#define PURPLE 0xF81F
+
+
+#define DIRECTION0 0
+#define DIRECTION90 1
+#define DIRECTION180 2
+#define DIRECTION270 3
+
+
+typedef struct {
+ uint16_t _width;
+ uint16_t _height;
+ uint16_t _offsetx;
+ uint16_t _offsety;
+ uint16_t _font_direction;
+ uint16_t _font_fill;
+ uint16_t _font_fill_color;
+ uint16_t _font_underline;
+ uint16_t _font_underline_color;
+ int16_t _dc;
+ int16_t _bl;
+ spi_device_handle_t _SPIHandle;
+} TFT_t;
+
+void spi_master_init(TFT_t * dev, int16_t GPIO_MOSI, int16_t GPIO_SCLK, int16_t GPIO_CS, int16_t GPIO_DC, int16_t GPIO_RESET, int16_t GPIO_BL);
+bool spi_master_write_byte(spi_device_handle_t SPIHandle, const uint8_t* Data, size_t DataLength);
+bool spi_master_write_command(TFT_t * dev, uint8_t cmd);
+bool spi_master_write_data_byte(TFT_t * dev, uint8_t data);
+bool spi_master_write_data_word(TFT_t * dev, uint16_t data);
+bool spi_master_write_addr(TFT_t * dev, uint16_t addr1, uint16_t addr2);
+bool spi_master_write_color(TFT_t * dev, uint16_t color, uint16_t size);
+bool spi_master_write_colors(TFT_t * dev, uint16_t * colors, uint16_t size);
+
+void delayMS(int ms);
+void lcdInit(TFT_t * dev, int width, int height, int offsetx, int offsety);
+void lcdDrawPixel(TFT_t * dev, uint16_t x, uint16_t y, uint16_t color);
+void lcdDrawMultiPixels(TFT_t * dev, uint16_t x, uint16_t y, uint16_t size, uint16_t * colors);
+void lcdDrawFillRect(TFT_t * dev, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color);
+void lcdDisplayOff(TFT_t * dev);
+void lcdDisplayOn(TFT_t * dev);
+void lcdFillScreen(TFT_t * dev, uint16_t color);
+void lcdDrawLine(TFT_t * dev, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color);
+void lcdDrawRect(TFT_t * dev, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color);
+void lcdDrawRectAngle(TFT_t * dev, uint16_t xc, uint16_t yc, uint16_t w, uint16_t h, uint16_t angle, uint16_t color);
+void lcdDrawTriangle(TFT_t * dev, uint16_t xc, uint16_t yc, uint16_t w, uint16_t h, uint16_t angle, uint16_t color);
+void lcdDrawCircle(TFT_t * dev, uint16_t x0, uint16_t y0, uint16_t r, uint16_t color);
+void lcdDrawFillCircle(TFT_t * dev, uint16_t x0, uint16_t y0, uint16_t r, uint16_t color);
+void lcdDrawRoundRect(TFT_t * dev, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t r, uint16_t color);
+void lcdDrawArrow(TFT_t * dev, uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t w, uint16_t color);
+void lcdDrawFillArrow(TFT_t * dev, uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t w, uint16_t color);
+uint16_t rgb565_conv(uint16_t r, uint16_t g, uint16_t b);
+int lcdDrawChar(TFT_t * dev, FontxFile *fx, uint16_t x, uint16_t y, uint8_t ascii, uint16_t color);
+int lcdDrawString(TFT_t * dev, FontxFile *fx, uint16_t x, uint16_t y, uint8_t * ascii, uint16_t color);
+int lcdDrawCode(TFT_t * dev, FontxFile *fx, uint16_t x,uint16_t y,uint8_t code,uint16_t color);
+//int lcdDrawUTF8Char(TFT_t * dev, FontxFile *fx, uint16_t x, uint16_t y, uint8_t *utf8, uint16_t color);
+//int lcdDrawUTF8String(TFT_t * dev, FontxFile *fx, uint16_t x, uint16_t y, unsigned char *utfs, uint16_t color);
+void lcdSetFontDirection(TFT_t * dev, uint16_t);
+void lcdSetFontFill(TFT_t * dev, uint16_t color);
+void lcdUnsetFontFill(TFT_t * dev);
+void lcdSetFontUnderLine(TFT_t * dev, uint16_t color);
+void lcdUnsetFontUnderLine(TFT_t * dev);
+void lcdBacklightOff(TFT_t * dev);
+void lcdBacklightOn(TFT_t * dev);
+void lcdInversionOff(TFT_t * dev);
+void lcdInversionOn(TFT_t * dev);
+#endif /* MAIN_ST7789_H_ */
+
diff --git a/main/utilities/letter_shell/port/esp-idf/CMakeLists.txt b/main/utilities/letter_shell/port/esp-idf/CMakeLists.txt
new file mode 100644
index 0000000..aad99df
--- /dev/null
+++ b/main/utilities/letter_shell/port/esp-idf/CMakeLists.txt
@@ -0,0 +1,8 @@
+idf_component_register(
+ SRCS "src/shell.c"
+ "src/shell_ext.c"
+ "shell_port.c"
+ INCLUDE_DIRS "./"
+ "./src"
+ LDFRAGMENTS "shell.lf"
+)
\ No newline at end of file
diff --git a/main/utilities/letter_shell/port/esp-idf/readme.md b/main/utilities/letter_shell/port/esp-idf/readme.md
new file mode 100644
index 0000000..d7dcf1e
--- /dev/null
+++ b/main/utilities/letter_shell/port/esp-idf/readme.md
@@ -0,0 +1,13 @@
+# esp-idf demo
+
+此目录文件用于在 `esp-idf` 中使用 `letter-shell` 做参考
+
+## 使用
+
+此 demo 已经包含 `CMakeLists.txt`, 可直接作为 `esp-idf` 的模块编译
+
+## 注意
+
+- `esp-idf` 编译系统会忽略 `__attribute__((used))` 声明,所以仅仅作为命令定义的函数不会被包含在编译出来的固件里面,只有被代码引用的函数会被编译进去
+
+- 此 demo 包含链接使用的 `.lf` 文件,在使用这个文件的情况下不需要修改 `esp-idf` 中的 `ld` 文件
diff --git a/main/utilities/letter_shell/port/esp-idf/shell.lf b/main/utilities/letter_shell/port/esp-idf/shell.lf
new file mode 100644
index 0000000..bd7f89c
--- /dev/null
+++ b/main/utilities/letter_shell/port/esp-idf/shell.lf
@@ -0,0 +1,13 @@
+[sections:shellCommand]
+entries:
+ shellCommand+
+
+[scheme:shell_command]
+entries:
+ shellCommand -> flash_rodata
+
+[mapping:shell]
+archive: *
+entries:
+ * (shell_command);
+ shellCommand -> flash_rodata KEEP() ALIGN(4, pre, post) SURROUND(shell_command)
\ No newline at end of file
diff --git a/main/utilities/letter_shell/port/esp-idf/shell_cfg.h b/main/utilities/letter_shell/port/esp-idf/shell_cfg.h
new file mode 100644
index 0000000..05b0446
--- /dev/null
+++ b/main/utilities/letter_shell/port/esp-idf/shell_cfg.h
@@ -0,0 +1,190 @@
+/**
+ * @file shell_cfg.h
+ * @author Letter (nevermindzzt@gmail.com)
+ * @brief shell config
+ * @version 3.0.0
+ * @date 2019-12-31
+ *
+ * @copyright (c) 2019 Letter
+ *
+ */
+
+#ifndef __SHELL_CFG_H__
+#define __SHELL_CFG_H__
+
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+
+/**
+ * @brief 是否使用默认shell任务while循环,使能宏`SHELL_USING_TASK`后此宏有意义
+ * 使能此宏,则`shellTask()`函数会一直循环读取输入,一般使用操作系统建立shell
+ * 任务时使能此宏,关闭此宏的情况下,一般适用于无操作系统,在主循环中调用`shellTask()`
+ */
+#define SHELL_TASK_WHILE 1
+
+/**
+ * @brief 是否使用命令导出方式
+ * 使能此宏后,可以使用`SHELL_EXPORT_CMD()`等导出命令
+ * 定义shell命令,关闭此宏的情况下,需要使用命令表的方式
+ */
+#define SHELL_USING_CMD_EXPORT 1
+
+/**
+ * @brief 是否使用shell伴生对象
+ * 一些扩展的组件(文件系统支持,日志工具等)需要使用伴生对象
+ */
+#define SHELL_USING_COMPANION 0
+
+/**
+ * @brief 支持shell尾行模式
+ */
+#define SHELL_SUPPORT_END_LINE 0
+
+/**
+ * @brief 是否在输出命令列表中列出用户
+ */
+#define SHELL_HELP_LIST_USER 0
+
+/**
+ * @brief 是否在输出命令列表中列出变量
+ */
+#define SHELL_HELP_LIST_VAR 0
+
+/**
+ * @brief 是否在输出命令列表中列出按键
+ */
+#define SHELL_HELP_LIST_KEY 0
+
+/**
+ * @brief 是否在输出命令列表中展示命令权限
+ */
+#define SHELL_HELP_SHOW_PERMISSION 1
+
+/**
+ * @brief 使用LF作为命令行回车触发
+ * 可以和SHELL_ENTER_CR同时开启
+ */
+#define SHELL_ENTER_LF 1
+
+/**
+ * @brief 使用CR作为命令行回车触发
+ * 可以和SHELL_ENTER_LF同时开启
+ */
+#define SHELL_ENTER_CR 1
+
+/**
+ * @brief 使用CRLF作为命令行回车触发
+ * 不可以和SHELL_ENTER_LF或SHELL_ENTER_CR同时开启
+ */
+#define SHELL_ENTER_CRLF 0
+
+/**
+ * @brief 使用执行未导出函数的功能
+ * 启用后,可以通过`exec [addr] [args]`直接执行对应地址的函数
+ * @attention 如果地址错误,可能会直接引起程序崩溃
+ */
+#define SHELL_EXEC_UNDEF_FUNC 0
+
+/**
+ * @brief shell命令参数最大数量
+ * 包含命令名在内,超过16个参数并且使用了参数自动转换的情况下,需要修改源码
+ */
+#define SHELL_PARAMETER_MAX_NUMBER 8
+
+/**
+ * @brief 历史命令记录数量
+ */
+#define SHELL_HISTORY_MAX_NUMBER 5
+
+/**
+ * @brief 双击间隔(ms)
+ * 使能宏`SHELL_LONG_HELP`后此宏生效,定义双击tab补全help的时间间隔
+ */
+#define SHELL_DOUBLE_CLICK_TIME 200
+
+/**
+ * @brief 快速帮助
+ * 作用于双击tab的场景,当使能此宏时,双击tab不会对命令进行help补全,而是直接显示对应命令的帮助信息
+ */
+#define SHELL_QUICK_HELP 1
+
+/**
+ * @brief 保存命令返回值
+ * 开启后会默认定义一个`RETVAL`变量,会保存上一次命令执行的返回值,可以在随后的命令中进行调用
+ * 如果命令的`SHELL_CMD_DISABLE_RETURN`标志被设置,则该命令不会更新`RETVAL`
+ */
+#define SHELL_KEEP_RETURN_VALUE 0
+
+/**
+ * @brief 管理的最大shell数量
+ */
+#define SHELL_MAX_NUMBER 5
+
+/**
+ * @brief shell格式化输出的缓冲大小
+ * 为0时不使用shell格式化输出
+ */
+#define SHELL_PRINT_BUFFER 128
+
+/**
+ * @brief shell格式化输入的缓冲大小
+ * 为0时不使用shell格式化输入
+ * @note shell格式化输入会阻塞shellTask, 仅适用于在有操作系统的情况下使用
+ */
+#define SHELL_SCAN_BUFFER 0
+
+/**
+ * @brief 获取系统时间(ms)
+ * 定义此宏为获取系统Tick,如`HAL_GetTick()`
+ * @note 此宏不定义时无法使用双击tab补全命令help,无法使用shell超时锁定
+ */
+#define SHELL_GET_TICK() xTaskGetTickCount()
+
+/**
+ * @brief 使用锁
+ * @note 使用shell锁时,需要对加锁和解锁进行实现
+ */
+#define SHELL_USING_LOCK 0
+
+/**
+ * @brief shell内存分配
+ * shell本身不需要此接口,若使用shell伴生对象,需要进行定义
+ */
+#define SHELL_MALLOC(size) 0
+
+/**
+ * @brief shell内存释放
+ * shell本身不需要此接口,若使用shell伴生对象,需要进行定义
+ */
+#define SHELL_FREE(obj) 0
+
+/**
+ * @brief 是否显示shell信息
+ */
+#define SHELL_SHOW_INFO 1
+
+/**
+ * @brief 是否在登录后清除命令行
+ */
+#define SHELL_CLS_WHEN_LOGIN 1
+
+/**
+ * @brief shell默认用户
+ */
+#define SHELL_DEFAULT_USER "letter"
+
+/**
+ * @brief shell默认用户密码
+ * 若默认用户不需要密码,设为""
+ */
+#define SHELL_DEFAULT_USER_PASSWORD ""
+
+/**
+ * @brief shell自动锁定超时
+ * shell当前用户密码有效的时候生效,超时后会自动重新锁定shell
+ * 设置为0时关闭自动锁定功能,时间单位为`SHELL_GET_TICK()`单位
+ * @note 使用超时锁定必须保证`SHELL_GET_TICK()`有效
+ */
+#define SHELL_LOCK_TIMEOUT 0 * 60 * 1000
+
+#endif
diff --git a/main/utilities/letter_shell/port/esp-idf/shell_port.c b/main/utilities/letter_shell/port/esp-idf/shell_port.c
new file mode 100644
index 0000000..d08b4f6
--- /dev/null
+++ b/main/utilities/letter_shell/port/esp-idf/shell_port.c
@@ -0,0 +1,70 @@
+/**
+ * @file shell_port.c
+ * @author Letter (NevermindZZT@gmail.com)
+ * @brief
+ * @version 0.1
+ * @date 2019-02-22
+ *
+ * @copyright (c) 2019 Letter
+ *
+ */
+
+#include "shell.h"
+#include "freertos/FreeRTOS.h"
+#include "driver/uart.h"
+
+
+#define SHELL_UART UART_NUM_0
+
+Shell shell;
+char shellBuffer[512];
+
+/**
+ * @brief 用户shell写
+ *
+ * @param data 数据
+ * @param len 数据长度
+ *
+ * @return unsigned short 写入实际长度
+ */
+unsigned short userShellWrite(char *data, unsigned short len)
+{
+ return uart_write_bytes(SHELL_UART, (const char *)data, len);
+}
+
+
+/**
+ * @brief 用户shell读
+ *
+ * @param data 数据
+ * @param len 数据长度
+ *
+ * @return unsigned short 读取实际长度
+ */
+signed char userShellRead(char *data, unsigned short len)
+{
+ return uart_read_bytes(SHELL_UART, (uint8_t *)data, len, portMAX_DELAY);
+}
+
+
+/**
+ * @brief 用户shell初始化
+ *
+ */
+void userShellInit(void)
+{
+ uart_config_t uartConfig = {
+ .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
+ };
+ uart_param_config(SHELL_UART, &uartConfig);
+ uart_driver_install(SHELL_UART, 256 * 2, 0, 0, NULL, 0);
+ shell.write = userShellWrite;
+ shell.read = userShellRead;
+ shellInit(&shell, shellBuffer, 512);
+
+ xTaskCreate(shellTask, "shell", 2048, &shell, 10, NULL);
+}
diff --git a/main/utilities/letter_shell/port/esp-idf/shell_port.h b/main/utilities/letter_shell/port/esp-idf/shell_port.h
new file mode 100644
index 0000000..0fd47ce
--- /dev/null
+++ b/main/utilities/letter_shell/port/esp-idf/shell_port.h
@@ -0,0 +1,20 @@
+/**
+ * @file shell_port.h
+ * @author Letter (NevermindZZT@gmail.com)
+ * @brief
+ * @version 0.1
+ * @date 2019-02-22
+ *
+ * @copyright (c) 2019 Letter
+ *
+ */
+
+#ifndef __SHELL_PORT_H__
+#define __SHELL_PORT_H__
+
+#include "shell.h"
+
+extern Shell shell;
+
+void userShellInit(void);
+#endif
diff --git a/main/utilities/letter_shell/src/shell.c b/main/utilities/letter_shell/src/shell.c
new file mode 100644
index 0000000..cc6ee33
--- /dev/null
+++ b/main/utilities/letter_shell/src/shell.c
@@ -0,0 +1,2011 @@
+/**
+ * @file shell.c
+ * @author Letter (NevermindZZT@gmail.com)
+ * @version 3.0.0
+ * @date 2019-12-30
+ *
+ * @copyright (c) 2020 Letter
+ *
+ */
+
+#include "shell.h"
+#include "string.h"
+#include "stdio.h"
+#include "stdarg.h"
+#include "shell_ext.h"
+
+
+#if SHELL_USING_CMD_EXPORT == 1
+/**
+ * @brief 默认用户
+ */
+const char shellCmdDefaultUser[] = SHELL_DEFAULT_USER;
+const char shellPasswordDefaultUser[] = SHELL_DEFAULT_USER_PASSWORD;
+const char shellDesDefaultUser[] = "default user";
+SHELL_USED const ShellCommand shellUserDefault SHELL_SECTION("shellCommand") =
+{
+ .attr.value = SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_USER),
+ .data.user.name = shellCmdDefaultUser,
+ .data.user.password = shellPasswordDefaultUser,
+ .data.user.desc = shellDesDefaultUser
+};
+#endif
+
+#if SHELL_USING_CMD_EXPORT == 1
+ #if defined(__CC_ARM) || (defined(__ARMCC_VERSION) && __ARMCC_VERSION >= 6000000)
+ extern const unsigned int shellCommand$$Base;
+ extern const unsigned int shellCommand$$Limit;
+ #elif defined(__ICCARM__) || defined(__ICCRX__)
+ #pragma section="shellCommand"
+ #elif defined(__GNUC__)
+ extern const unsigned int _shell_command_start;
+ extern const unsigned int _shell_command_end;
+ #endif
+#else
+ extern const ShellCommand shellCommandList[];
+ extern const unsigned short shellCommandCount;
+#endif
+
+
+/**
+ * @brief shell 常量文本索引
+ */
+enum
+{
+#if SHELL_SHOW_INFO == 1
+ SHELL_TEXT_INFO, /**< shell信息 */
+#endif
+ SHELL_TEXT_CMD_TOO_LONG, /**< 命令过长 */
+ SHELL_TEXT_CMD_LIST, /**< 可执行命令列表标题 */
+ SHELL_TEXT_VAR_LIST, /**< 变量列表标题 */
+ SHELL_TEXT_USER_LIST, /**< 用户列表标题 */
+ SHELL_TEXT_KEY_LIST, /**< 按键列表标题 */
+ SHELL_TEXT_CMD_NOT_FOUND, /**< 命令未找到 */
+ SHELL_TEXT_POINT_CANNOT_MODIFY, /**< 指针变量不允许修改 */
+ SHELL_TEXT_VAR_READ_ONLY_CANNOT_MODIFY, /**< 只读变量不允许修改 */
+ SHELL_TEXT_NOT_VAR, /**< 命令不是变量 */
+ SHELL_TEXT_VAR_NOT_FOUND, /**< 变量未找到 */
+ SHELL_TEXT_HELP_HEADER, /**< help头 */
+ SHELL_TEXT_PASSWORD_HINT, /**< 密码输入提示 */
+ SHELL_TEXT_PASSWORD_ERROR, /**< 密码错误 */
+ SHELL_TEXT_CLEAR_CONSOLE, /**< 清空控制台 */
+ SHELL_TEXT_CLEAR_LINE, /**< 清空当前行 */
+ SHELL_TEXT_TYPE_CMD, /**< 命令类型 */
+ SHELL_TEXT_TYPE_VAR, /**< 变量类型 */
+ SHELL_TEXT_TYPE_USER, /**< 用户类型 */
+ SHELL_TEXT_TYPE_KEY, /**< 按键类型 */
+ SHELL_TEXT_TYPE_NONE, /**< 非法类型 */
+#if SHELL_EXEC_UNDEF_FUNC == 1
+ SHELL_TEXT_PARAM_ERROR, /**< 参数错误 */
+#endif
+};
+
+
+static const char *shellText[] =
+{
+#if SHELL_SHOW_INFO == 1
+ [SHELL_TEXT_INFO] =
+ "\r\n"
+ " _ _ _ _ _ _ \r\n"
+ "| | ___| |_| |_ ___ _ __ ___| |__ ___| | |\r\n"
+ "| | / _ \\ __| __/ _ \\ '__| / __| '_ \\ / _ \\ | |\r\n"
+ "| |__| __/ |_| || __/ | \\__ \\ | | | __/ | |\r\n"
+ "|_____\\___|\\__|\\__\\___|_| |___/_| |_|\\___|_|_|\r\n"
+ "\r\n"
+ "Build: "__DATE__" "__TIME__"\r\n"
+ "Version: "SHELL_VERSION"\r\n"
+ "Copyright: (c) 2020 Letter\r\n",
+#endif
+ [SHELL_TEXT_CMD_TOO_LONG] =
+ "\r\nWarning: Command is too long\r\n",
+ [SHELL_TEXT_CMD_LIST] =
+ "\r\nCommand List:\r\n",
+ [SHELL_TEXT_VAR_LIST] =
+ "\r\nVar List:\r\n",
+ [SHELL_TEXT_USER_LIST] =
+ "\r\nUser List:\r\n",
+ [SHELL_TEXT_KEY_LIST] =
+ "\r\nKey List:\r\n",
+ [SHELL_TEXT_CMD_NOT_FOUND] =
+ "Command not Found\r\n",
+ [SHELL_TEXT_POINT_CANNOT_MODIFY] =
+ "can't set pointer\r\n",
+ [SHELL_TEXT_VAR_READ_ONLY_CANNOT_MODIFY] =
+ "can't set read only var\r\n",
+ [SHELL_TEXT_NOT_VAR] =
+ " is not a var\r\n",
+ [SHELL_TEXT_VAR_NOT_FOUND] =
+ "Var not Fount\r\n",
+ [SHELL_TEXT_HELP_HEADER] =
+ "command help of ",
+ [SHELL_TEXT_PASSWORD_HINT] =
+ "Please input password:",
+ [SHELL_TEXT_PASSWORD_ERROR] =
+ "\r\npassword error\r\n",
+ [SHELL_TEXT_CLEAR_CONSOLE] =
+ "\033[2J\033[1H",
+ [SHELL_TEXT_CLEAR_LINE] =
+ "\033[2K\r",
+ [SHELL_TEXT_TYPE_CMD] =
+ "CMD ",
+ [SHELL_TEXT_TYPE_VAR] =
+ "VAR ",
+ [SHELL_TEXT_TYPE_USER] =
+ "USER",
+ [SHELL_TEXT_TYPE_KEY] =
+ "KEY ",
+ [SHELL_TEXT_TYPE_NONE] =
+ "NONE",
+#if SHELL_EXEC_UNDEF_FUNC == 1
+ [SHELL_TEXT_PARAM_ERROR] =
+ "Parameter error\r\n",
+#endif
+};
+
+
+/**
+ * @brief shell对象表
+ */
+static Shell *shellList[SHELL_MAX_NUMBER] = {NULL};
+
+
+static void shellAdd(Shell *shell);
+static void shellWritePrompt(Shell *shell, unsigned char newline);
+static void shellWriteReturnValue(Shell *shell, int value);
+static int shellShowVar(Shell *shell, ShellCommand *command);
+void shellSetUser(Shell *shell, const ShellCommand *user);
+ShellCommand* shellSeekCommand(Shell *shell,
+ const char *cmd,
+ ShellCommand *base,
+ unsigned short compareLength);
+static void shellWriteCommandHelp(Shell *shell, char *cmd);
+
+/**
+ * @brief shell 初始化
+ *
+ * @param shell shell对象
+ */
+void shellInit(Shell *shell, char *buffer, unsigned short size)
+{
+ shell->parser.length = 0;
+ shell->parser.cursor = 0;
+ shell->info.user = NULL;
+ shell->status.isChecked = 1;
+
+ shell->parser.buffer = buffer;
+ shell->parser.bufferSize = size / (SHELL_HISTORY_MAX_NUMBER + 1);
+
+#if SHELL_HISTORY_MAX_NUMBER > 0
+ shell->history.offset = 0;
+ shell->history.number = 0;
+ shell->history.record = 0;
+ for (short i = 0; i < SHELL_HISTORY_MAX_NUMBER; i++)
+ {
+ shell->history.item[i] = buffer + shell->parser.bufferSize * (i + 1);
+ }
+#endif /** SHELL_HISTORY_MAX_NUMBER > 0 */
+
+#if SHELL_USING_CMD_EXPORT == 1
+ #if defined(__CC_ARM) || (defined(__ARMCC_VERSION) && __ARMCC_VERSION >= 6000000)
+ shell->commandList.base = (ShellCommand *)(&shellCommand$$Base);
+ shell->commandList.count = ((unsigned int)(&shellCommand$$Limit)
+ - (unsigned int)(&shellCommand$$Base))
+ / sizeof(ShellCommand);
+
+ #elif defined(__ICCARM__) || defined(__ICCRX__)
+ shell->commandList.base = (ShellCommand *)(__section_begin("shellCommand"));
+ shell->commandList.count = ((unsigned int)(__section_end("shellCommand"))
+ - (unsigned int)(__section_begin("shellCommand")))
+ / sizeof(ShellCommand);
+ #elif defined(__GNUC__)
+ shell->commandList.base = (ShellCommand *)(&_shell_command_start);
+ shell->commandList.count = ((unsigned int)(&_shell_command_end)
+ - (unsigned int)(&_shell_command_start))
+ / sizeof(ShellCommand);
+ #else
+ #error not supported compiler, please use command table mode
+ #endif
+#else
+ shell->commandList.base = (ShellCommand *)shellCommandList;
+ shell->commandList.count = shellCommandCount;
+#endif
+
+ shellAdd(shell);
+
+ shellSetUser(shell, shellSeekCommand(shell,
+ SHELL_DEFAULT_USER,
+ shell->commandList.base,
+ 0));
+ shellWritePrompt(shell, 1);
+}
+
+
+/**
+ * @brief 添加shell
+ *
+ * @param shell shell对象
+ */
+static void shellAdd(Shell *shell)
+{
+ for (short i = 0; i < SHELL_MAX_NUMBER; i++)
+ {
+ if (shellList[i] == NULL)
+ {
+ shellList[i] = shell;
+ return;
+ }
+ }
+}
+
+/**
+ * @brief 移除shell
+ *
+ * @param shell shell对象
+ *
+ */
+void shellRemove(Shell *shell)
+{
+ for (short i = 0; i < SHELL_MAX_NUMBER; i++)
+ {
+ if (shellList[i] == shell)
+ {
+ shellList[i] = NULL;
+ return;
+ }
+ }
+}
+
+/**
+ * @brief 获取当前活动shell
+ *
+ * @return Shell* 当前活动shell对象
+ */
+Shell* shellGetCurrent(void)
+{
+ for (short i = 0; i < SHELL_MAX_NUMBER; i++)
+ {
+ if (shellList[i] && shellList[i]->status.isActive)
+ {
+ return shellList[i];
+ }
+ }
+ return NULL;
+}
+
+
+/**
+ * @brief shell写字符
+ *
+ * @param shell shell对象
+ * @param data 字符数据
+ */
+static void shellWriteByte(Shell *shell, char data)
+{
+ shell->write(&data, 1);
+}
+
+
+/**
+ * @brief shell 写字符串
+ *
+ * @param shell shell对象
+ * @param string 字符串数据
+ *
+ * @return unsigned short 写入字符的数量
+ */
+unsigned short shellWriteString(Shell *shell, const char *string)
+{
+ unsigned short count = 0;
+ const char *p = string;
+ SHELL_ASSERT(shell->write, return 0);
+ while(*p++)
+ {
+ count ++;
+ }
+ return shell->write((char *)string, count);
+}
+
+
+/**
+ * @brief shell 写命令描述字符串
+ *
+ * @param shell shell对象
+ * @param string 字符串数据
+ *
+ * @return unsigned short 写入字符的数量
+ */
+static unsigned short shellWriteCommandDesc(Shell *shell, const char *string)
+{
+ unsigned short count = 0;
+ const char *p = string;
+ SHELL_ASSERT(shell->write, return 0);
+ while (*p && *p != '\r' && *p != '\n')
+ {
+ p++;
+ count++;
+ }
+
+ if (count > 36)
+ {
+ shell->write((char *)string, 36);
+ shell->write("...", 3);
+ }
+ else
+ {
+ shell->write((char *)string, count);
+ }
+ return count > 36 ? 36 : 39;
+}
+
+
+/**
+ * @brief shell写命令提示符
+ *
+ * @param shell shell对象
+ * @param newline 新行
+ *
+ */
+static void shellWritePrompt(Shell *shell, unsigned char newline)
+{
+ if (shell->status.isChecked)
+ {
+ if (newline)
+ {
+ shellWriteString(shell, "\r\n");
+ }
+ shellWriteString(shell, shell->info.user->data.user.name);
+ shellWriteString(shell, ":");
+ shellWriteString(shell, shell->info.path ? shell->info.path : "/");
+ shellWriteString(shell, "$ ");
+ }
+ else
+ {
+ shellWriteString(shell, shellText[SHELL_TEXT_PASSWORD_HINT]);
+ }
+}
+
+
+#if SHELL_PRINT_BUFFER > 0
+/**
+ * @brief shell格式化输出
+ *
+ * @param shell shell对象
+ * @param fmt 格式化字符串
+ * @param ... 参数
+ */
+void shellPrint(Shell *shell, const char *fmt, ...)
+{
+ char buffer[SHELL_PRINT_BUFFER];
+ va_list vargs;
+
+ SHELL_ASSERT(shell, return);
+
+ va_start(vargs, fmt);
+ vsnprintf(buffer, SHELL_PRINT_BUFFER - 1, fmt, vargs);
+ va_end(vargs);
+
+ shellWriteString(shell, buffer);
+}
+#endif
+
+
+#if SHELL_SCAN_BUFFER > 0
+/**
+ * @brief shell格式化输入
+ *
+ * @param shell shell对象
+ * @param fmt 格式化字符串
+ * @param ... 参数
+ */
+void shellScan(Shell *shell, char *fmt, ...)
+{
+ char buffer[SHELL_SCAN_BUFFER];
+ va_list vargs;
+ short index = 0;
+
+ SHELL_ASSERT(shell, return);
+
+ if (shell->read)
+ {
+ do {
+ if (shell->read(&buffer[index], 1) == 1)
+ {
+ shell->write(&buffer[index], 1);
+ index++;
+ }
+ } while (buffer[index -1] != '\r' && buffer[index -1] != '\n' && index < SHELL_SCAN_BUFFER);
+ shellWriteString(shell, "\r\n");
+ buffer[index] = '\0';
+ }
+
+ va_start(vargs, fmt);
+ vsscanf(buffer, fmt, vargs);
+ va_end(vargs);
+}
+#endif
+
+
+/**
+ * @brief shell 检查命令权限
+ *
+ * @param shell shell对象
+ * @param command ShellCommand
+ *
+ * @return signed char 0 当前用户具有该命令权限
+ * @return signec char -1 当前用户不具有该命令权限
+ */
+signed char shellCheckPermission(Shell *shell, ShellCommand *command)
+{
+ return ((!command->attr.attrs.permission
+ || command->attr.attrs.type == SHELL_TYPE_USER
+ || (shell->info.user
+ && (command->attr.attrs.permission
+ & shell->info.user->attr.attrs.permission)))
+ && (shell->status.isChecked
+ || command->attr.attrs.enableUnchecked))
+ ? 0 : -1;
+}
+
+
+/**
+ * @brief int转16进制字符串
+ *
+ * @param value 数值
+ * @param buffer 缓冲
+ *
+ * @return signed char 转换后有效数据长度
+ */
+signed char shellToHex(unsigned int value, char *buffer)
+{
+ char byte;
+ unsigned char i = 8;
+ buffer[8] = 0;
+ while (value)
+ {
+ byte = value & 0x0000000F;
+ buffer[--i] = (byte > 9) ? (byte + 87) : (byte + 48);
+ value >>= 4;
+ }
+ return 8 - i;
+}
+
+
+/**
+* @brief int转10进制字符串
+ *
+ * @param value 数值
+ * @param buffer 缓冲
+ *
+ * @return signed char 转换后有效数据长度
+ */
+signed char shellToDec(int value, char *buffer)
+{
+ unsigned char i = 11;
+ int v = value;
+ if (value < 0)
+ {
+ v = -value;
+ }
+ buffer[11] = 0;
+ while (v)
+ {
+ buffer[--i] = v % 10 + 48;
+ v /= 10;
+ }
+ if (value < 0)
+ {
+ buffer[--i] = '-';
+ }
+ if (value == 0) {
+ buffer[--i] = '0';
+ }
+ return 11 - i;
+}
+
+
+/**
+ * @brief shell字符串复制
+ *
+ * @param dest 目标字符串
+ * @param src 源字符串
+ * @return unsigned short 字符串长度
+ */
+static unsigned short shellStringCopy(char *dest, char* src)
+{
+ unsigned short count = 0;
+ while (*(src + count))
+ {
+ *(dest + count) = *(src + count);
+ count++;
+ }
+ *(dest + count) = 0;
+ return count;
+}
+
+
+/**
+ * @brief shell字符串比较
+ *
+ * @param dest 目标字符串
+ * @param src 源字符串
+ * @return unsigned short 匹配长度
+ */
+static unsigned short shellStringCompare(char* dest, char *src)
+{
+ unsigned short match = 0;
+ unsigned short i = 0;
+
+ while (*(dest +i) && *(src + i))
+ {
+ if (*(dest + i) != *(src +i))
+ {
+ break;
+ }
+ match ++;
+ i++;
+ }
+ return match;
+}
+
+
+/**
+ * @brief shell获取命令名
+ *
+ * @param command 命令
+ * @return const char* 命令名
+ */
+static const char* shellGetCommandName(ShellCommand *command)
+{
+ static char buffer[9];
+ for (unsigned char i = 0; i < 9; i++)
+ {
+ buffer[i] = '0';
+ }
+ if (command->attr.attrs.type <= SHELL_TYPE_CMD_FUNC)
+ {
+ return command->data.cmd.name;
+ }
+ else if (command->attr.attrs.type <= SHELL_TYPE_VAR_NODE)
+ {
+ return command->data.var.name;
+ }
+ else if (command->attr.attrs.type <= SHELL_TYPE_USER)
+ {
+ return command->data.user.name;
+ }
+ else
+ {
+ shellToHex(command->data.key.value, buffer);
+ return buffer;
+ }
+}
+
+
+/**
+ * @brief shell获取命令描述
+ *
+ * @param command 命令
+ * @return const char* 命令描述
+ */
+static const char* shellGetCommandDesc(ShellCommand *command)
+{
+ if (command->attr.attrs.type <= SHELL_TYPE_CMD_FUNC)
+ {
+ return command->data.cmd.desc;
+ }
+ else if (command->attr.attrs.type <= SHELL_TYPE_VAR_NODE)
+ {
+ return command->data.var.desc;
+ }
+ else if (command->attr.attrs.type <= SHELL_TYPE_USER)
+ {
+ return command->data.user.desc;
+ }
+ else
+ {
+ return command->data.key.desc;
+ }
+}
+
+/**
+ * @brief shell 列出命令条目
+ *
+ * @param shell shell对象
+ * @param item 命令条目
+ */
+void shellListItem(Shell *shell, ShellCommand *item)
+{
+ short spaceLength;
+
+ spaceLength = 22 - shellWriteString(shell, shellGetCommandName(item));
+ spaceLength = (spaceLength > 0) ? spaceLength : 4;
+ do {
+ shellWriteByte(shell, ' ');
+ } while (--spaceLength);
+ if (item->attr.attrs.type <= SHELL_TYPE_CMD_FUNC)
+ {
+ shellWriteString(shell, shellText[SHELL_TEXT_TYPE_CMD]);
+ }
+ else if (item->attr.attrs.type <= SHELL_TYPE_VAR_NODE)
+ {
+ shellWriteString(shell, shellText[SHELL_TEXT_TYPE_VAR]);
+ }
+ else if (item->attr.attrs.type <= SHELL_TYPE_USER)
+ {
+ shellWriteString(shell, shellText[SHELL_TEXT_TYPE_USER]);
+ }
+ else if (item->attr.attrs.type <= SHELL_TYPE_KEY)
+ {
+ shellWriteString(shell, shellText[SHELL_TEXT_TYPE_KEY]);
+ }
+ else
+ {
+ shellWriteString(shell, shellText[SHELL_TEXT_TYPE_NONE]);
+ }
+#if SHELL_HELP_SHOW_PERMISSION == 1
+ shellWriteString(shell, " ");
+ for (signed char i = 7; i >= 0; i--)
+ {
+ shellWriteByte(shell, item->attr.attrs.permission & (1 << i) ? 'x' : '-');
+ }
+#endif
+ shellWriteString(shell, " ");
+ shellWriteCommandDesc(shell, shellGetCommandDesc(item));
+ shellWriteString(shell, "\r\n");
+}
+
+
+/**
+ * @brief shell列出可执行命令
+ *
+ * @param shell shell对象
+ */
+void shellListCommand(Shell *shell)
+{
+ ShellCommand *base = (ShellCommand *)shell->commandList.base;
+ shellWriteString(shell, shellText[SHELL_TEXT_CMD_LIST]);
+ for (short i = 0; i < shell->commandList.count; i++)
+ {
+ if (base[i].attr.attrs.type <= SHELL_TYPE_CMD_FUNC
+ && shellCheckPermission(shell, &base[i]) == 0)
+ {
+ shellListItem(shell, &base[i]);
+ }
+ }
+}
+
+
+/**
+ * @brief shell列出变量
+ *
+ * @param shell shell对象
+ */
+void shellListVar(Shell *shell)
+{
+ ShellCommand *base = (ShellCommand *)shell->commandList.base;
+ shellWriteString(shell, shellText[SHELL_TEXT_VAR_LIST]);
+ for (short i = 0; i < shell->commandList.count; i++)
+ {
+ if (base[i].attr.attrs.type > SHELL_TYPE_CMD_FUNC
+ && base[i].attr.attrs.type <= SHELL_TYPE_VAR_NODE
+ && shellCheckPermission(shell, &base[i]) == 0)
+ {
+ shellListItem(shell, &base[i]);
+ }
+ }
+}
+
+
+/**
+ * @brief shell列出用户
+ *
+ * @param shell shell对象
+ */
+void shellListUser(Shell *shell)
+{
+ ShellCommand *base = (ShellCommand *)shell->commandList.base;
+ shellWriteString(shell, shellText[SHELL_TEXT_USER_LIST]);
+ for (short i = 0; i < shell->commandList.count; i++)
+ {
+ if (base[i].attr.attrs.type > SHELL_TYPE_VAR_NODE
+ && base[i].attr.attrs.type <= SHELL_TYPE_USER
+ && shellCheckPermission(shell, &base[i]) == 0)
+ {
+ shellListItem(shell, &base[i]);
+ }
+ }
+}
+
+
+/**
+ * @brief shell列出按键
+ *
+ * @param shell shell对象
+ */
+void shellListKey(Shell *shell)
+{
+ ShellCommand *base = (ShellCommand *)shell->commandList.base;
+ shellWriteString(shell, shellText[SHELL_TEXT_KEY_LIST]);
+ for (short i = 0; i < shell->commandList.count; i++)
+ {
+ if (base[i].attr.attrs.type > SHELL_TYPE_USER
+ && base[i].attr.attrs.type <= SHELL_TYPE_KEY
+ && shellCheckPermission(shell, &base[i]) == 0)
+ {
+ shellListItem(shell, &base[i]);
+ }
+ }
+}
+
+
+/**
+ * @brief shell列出所有命令
+ *
+ * @param shell shell对象
+ */
+void shellListAll(Shell *shell)
+{
+#if SHELL_HELP_LIST_USER == 1
+ shellListUser(shell);
+#endif
+ shellListCommand(shell);
+#if SHELL_HELP_LIST_VAR == 1
+ shellListVar(shell);
+#endif
+#if SHELL_HELP_LIST_KEY == 1
+ shellListKey(shell);
+#endif
+}
+
+
+/**
+ * @brief shell删除命令行数据
+ *
+ * @param shell shell对象
+ * @param length 删除长度
+ */
+void shellDeleteCommandLine(Shell *shell, unsigned char length)
+{
+ while (length--)
+ {
+ shellWriteString(shell, "\b \b");
+ }
+}
+
+
+/**
+ * @brief shell 清空命令行输入
+ *
+ * @param shell shell对象
+ */
+void shellClearCommandLine(Shell *shell)
+{
+ for (short i = shell->parser.length - shell->parser.cursor; i > 0; i--)
+ {
+ shellWriteByte(shell, ' ');
+ }
+ shellDeleteCommandLine(shell, shell->parser.length);
+}
+
+
+/**
+ * @brief shell插入一个字符到光标位置
+ *
+ * @param shell shell对象
+ * @param data 字符数据
+ */
+void shellInsertByte(Shell *shell, char data)
+{
+ /* 判断输入数据是否过长 */
+ if (shell->parser.length >= shell->parser.bufferSize - 1)
+ {
+ shellWriteString(shell, shellText[SHELL_TEXT_CMD_TOO_LONG]);
+ shellWritePrompt(shell, 1);
+ shellWriteString(shell, shell->parser.buffer);
+ return;
+ }
+
+ /* 插入数据 */
+ if (shell->parser.cursor == shell->parser.length)
+ {
+ shell->parser.buffer[shell->parser.length++] = data;
+ shell->parser.buffer[shell->parser.length] = 0;
+ shell->parser.cursor++;
+ shellWriteByte(shell, data);
+ }
+ else if (shell->parser.cursor < shell->parser.length)
+ {
+ for (short i = shell->parser.length - shell->parser.cursor; i > 0; i--)
+ {
+ shell->parser.buffer[shell->parser.cursor + i] =
+ shell->parser.buffer[shell->parser.cursor + i - 1];
+ }
+ shell->parser.buffer[shell->parser.cursor++] = data;
+ shell->parser.buffer[++shell->parser.length] = 0;
+ for (short i = shell->parser.cursor - 1; i < shell->parser.length; i++)
+ {
+ shellWriteByte(shell, shell->parser.buffer[i]);
+ }
+ for (short i = shell->parser.length - shell->parser.cursor; i > 0; i--)
+ {
+ shellWriteByte(shell, '\b');
+ }
+ }
+}
+
+
+/**
+ * @brief shell 删除字节
+ *
+ * @param shell shell对象
+ * @param direction 删除方向 {@code 1}删除光标前字符 {@code -1}删除光标处字符
+ */
+void shellDeleteByte(Shell *shell, signed char direction)
+{
+ char offset = (direction == -1) ? 1 : 0;
+
+ if ((shell->parser.cursor == 0 && direction == 1)
+ || (shell->parser.cursor == shell->parser.length && direction == -1))
+ {
+ return;
+ }
+ if (shell->parser.cursor == shell->parser.length && direction == 1)
+ {
+ shell->parser.cursor--;
+ shell->parser.length--;
+ shell->parser.buffer[shell->parser.length] = 0;
+ shellDeleteCommandLine(shell, 1);
+ }
+ else
+ {
+ for (short i = offset; i < shell->parser.length - shell->parser.cursor; i++)
+ {
+ shell->parser.buffer[shell->parser.cursor + i - 1] =
+ shell->parser.buffer[shell->parser.cursor + i];
+ }
+ shell->parser.length--;
+ if (!offset)
+ {
+ shell->parser.cursor--;
+ shellWriteByte(shell, '\b');
+ }
+ shell->parser.buffer[shell->parser.length] = 0;
+ for (short i = shell->parser.cursor; i < shell->parser.length; i++)
+ {
+ shellWriteByte(shell, shell->parser.buffer[i]);
+ }
+ shellWriteByte(shell, ' ');
+ for (short i = shell->parser.length - shell->parser.cursor + 1; i > 0; i--)
+ {
+ shellWriteByte(shell, '\b');
+ }
+ }
+}
+
+
+/**
+ * @brief shell 解析参数
+ *
+ * @param shell shell对象
+ */
+static void shellParserParam(Shell *shell)
+{
+ unsigned char quotes = 0;
+ unsigned char record = 1;
+
+ for (short i = 0; i < SHELL_PARAMETER_MAX_NUMBER; i++)
+ {
+ shell->parser.param[i] = NULL;
+ }
+
+ shell->parser.paramCount = 0;
+ for (unsigned short i = 0; i < shell->parser.length; i++)
+ {
+ if (quotes != 0
+ || (shell->parser.buffer[i] != ' '
+ && shell->parser.buffer[i] != 0))
+ {
+ if (shell->parser.buffer[i] == '\"')
+ {
+ quotes = quotes ? 0 : 1;
+ }
+ if (record == 1)
+ {
+ if (shell->parser.paramCount < SHELL_PARAMETER_MAX_NUMBER)
+ {
+ shell->parser.param[shell->parser.paramCount++] =
+ &(shell->parser.buffer[i]);
+ }
+ record = 0;
+ }
+ if (shell->parser.buffer[i] == '\\'
+ && shell->parser.buffer[i + 1] != 0)
+ {
+ i++;
+ }
+ }
+ else
+ {
+ shell->parser.buffer[i] = 0;
+ record = 1;
+ }
+ }
+}
+
+
+/**
+ * @brief shell去除字符串参数头尾的双引号
+ *
+ * @param shell shell对象
+ */
+static void shellRemoveParamQuotes(Shell *shell)
+{
+ unsigned short paramLength;
+ for (unsigned short i = 0; i < shell->parser.paramCount; i++)
+ {
+ if (shell->parser.param[i][0] == '\"')
+ {
+ shell->parser.param[i][0] = 0;
+ shell->parser.param[i] = &shell->parser.param[i][1];
+ }
+ paramLength = strlen(shell->parser.param[i]);
+ if (shell->parser.param[i][paramLength - 1] == '\"')
+ {
+ shell->parser.param[i][paramLength - 1] = 0;
+ }
+ }
+}
+
+
+/**
+ * @brief shell匹配命令
+ *
+ * @param shell shell对象
+ * @param cmd 命令
+ * @param base 匹配命令表基址
+ * @param compareLength 匹配字符串长度
+ * @return ShellCommand* 匹配到的命令
+ */
+ShellCommand* shellSeekCommand(Shell *shell,
+ const char *cmd,
+ ShellCommand *base,
+ unsigned short compareLength)
+{
+ const char *name;
+ unsigned short count = shell->commandList.count -
+ ((int)base - (int)shell->commandList.base) / sizeof(ShellCommand);
+ for (unsigned short i = 0; i < count; i++)
+ {
+ if (base[i].attr.attrs.type == SHELL_TYPE_KEY
+ || shellCheckPermission(shell, &base[i]) != 0)
+ {
+ continue;
+ }
+ name = shellGetCommandName(&base[i]);
+ if (!compareLength)
+ {
+ if (strcmp(cmd, name) == 0)
+ {
+ return &base[i];
+ }
+ }
+ else
+ {
+ if (strncmp(cmd, name, compareLength) == 0)
+ {
+ return &base[i];
+ }
+ }
+ }
+ return NULL;
+}
+
+
+/**
+ * @brief shell 获取变量值
+ *
+ * @param shell shell对象
+ * @param command 命令
+ * @return int 变量值
+ */
+int shellGetVarValue(Shell *shell, ShellCommand *command)
+{
+ int value = 0;
+ switch (command->attr.attrs.type)
+ {
+ case SHELL_TYPE_VAR_INT:
+ value = *((int *)(command->data.var.value));
+ break;
+ case SHELL_TYPE_VAR_SHORT:
+ value = *((short *)(command->data.var.value));
+ break;
+ case SHELL_TYPE_VAR_CHAR:
+ value = *((char *)(command->data.var.value));
+ break;
+ case SHELL_TYPE_VAR_STRING:
+ case SHELL_TYPE_VAR_POINT:
+ value = (int)(command->data.var.value);
+ break;
+ case SHELL_TYPE_VAR_NODE:
+ value = ((ShellNodeVarAttr *)command->data.var.value)->get ?
+ ((ShellNodeVarAttr *)command->data.var.value)
+ ->get(((ShellNodeVarAttr *)command->data.var.value)->var) : 0;
+ break;
+ default:
+ break;
+ }
+ return value;
+}
+
+
+/**
+ * @brief shell设置变量值
+ *
+ * @param shell shell对象
+ * @param command 命令
+ * @param value 值
+ * @return int 返回变量值
+ */
+int shellSetVarValue(Shell *shell, ShellCommand *command, int value)
+{
+ if (command->attr.attrs.readOnly)
+ {
+ shellWriteString(shell, shellText[SHELL_TEXT_VAR_READ_ONLY_CANNOT_MODIFY]);
+ }
+ else
+ {
+ switch (command->attr.attrs.type)
+ {
+ case SHELL_TYPE_VAR_INT:
+ *((int *)(command->data.var.value)) = value;
+ break;
+ case SHELL_TYPE_VAR_SHORT:
+ *((short *)(command->data.var.value)) = value;
+ break;
+ case SHELL_TYPE_VAR_CHAR:
+ *((char *)(command->data.var.value)) = value;
+ break;
+ case SHELL_TYPE_VAR_STRING:
+ shellStringCopy(((char *)(command->data.var.value)), (char *)value);
+ break;
+ case SHELL_TYPE_VAR_POINT:
+ shellWriteString(shell, shellText[SHELL_TEXT_POINT_CANNOT_MODIFY]);
+ break;
+ case SHELL_TYPE_VAR_NODE:
+ if (((ShellNodeVarAttr *)command->data.var.value)->set)
+ {
+ if (((ShellNodeVarAttr *)command->data.var.value)->var)
+ {
+ ((ShellNodeVarAttr *)command->data.var.value)
+ ->set(((ShellNodeVarAttr *)command->data.var.value)->var, value);
+ }
+ else
+ {
+ ((ShellNodeVarAttr *)command->data.var.value)->set(value);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ return shellShowVar(shell, command);
+}
+
+
+/**
+ * @brief shell变量输出
+ *
+ * @param shell shell对象
+ * @param command 命令
+ * @return int 返回变量值
+ */
+static int shellShowVar(Shell *shell, ShellCommand *command)
+{
+ char buffer[12] = "00000000000";
+ int value = shellGetVarValue(shell, command);
+
+ shellWriteString(shell, command->data.var.name);
+ shellWriteString(shell, " = ");
+
+ switch (command->attr.attrs.type)
+ {
+ case SHELL_TYPE_VAR_STRING:
+ shellWriteString(shell, "\"");
+ shellWriteString(shell, (char *)value);
+ shellWriteString(shell, "\"");
+ break;
+ // case SHELL_TYPE_VAR_INT:
+ // case SHELL_TYPE_VAR_SHORT:
+ // case SHELL_TYPE_VAR_CHAR:
+ // case SHELL_TYPE_VAR_POINT:
+ default:
+ shellWriteString(shell, &buffer[11 - shellToDec(value, buffer)]);
+ shellWriteString(shell, ", 0x");
+ for (short i = 0; i < 11; i++)
+ {
+ buffer[i] = '0';
+ }
+ shellToHex(value, buffer);
+ shellWriteString(shell, buffer);
+ break;
+ }
+
+ shellWriteString(shell, "\r\n");
+ return value;
+}
+
+
+/**
+ * @brief shell设置变量
+ *
+ * @param name 变量名
+ * @param value 变量值
+ * @return int 返回变量值
+ */
+int shellSetVar(char *name, int value)
+{
+ Shell *shell = shellGetCurrent();
+ if (shell == NULL)
+ {
+ return 0;
+ }
+ ShellCommand *command = shellSeekCommand(shell,
+ name,
+ shell->commandList.base,
+ 0);
+ if (!command)
+ {
+ shellWriteString(shell, shellText[SHELL_TEXT_VAR_NOT_FOUND]);
+ return 0;
+ }
+ if (command->attr.attrs.type < SHELL_TYPE_VAR_INT
+ || command->attr.attrs.type > SHELL_TYPE_VAR_NODE)
+ {
+ shellWriteString(shell, name);
+ shellWriteString(shell, shellText[SHELL_TEXT_NOT_VAR]);
+ return 0;
+ }
+ return shellSetVarValue(shell, command, value);
+}
+SHELL_EXPORT_CMD(
+SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_DISABLE_RETURN,
+setVar, shellSetVar, set var);
+
+
+/**
+ * @brief shell运行命令
+ *
+ * @param shell shell对象
+ * @param command 命令
+ *
+ * @return unsigned int 命令返回值
+ */
+unsigned int shellRunCommand(Shell *shell, ShellCommand *command)
+{
+ int returnValue = 0;
+ shell->status.isActive = 1;
+ if (command->attr.attrs.type == SHELL_TYPE_CMD_MAIN)
+ {
+ shellRemoveParamQuotes(shell);
+ returnValue = command->data.cmd.function(shell->parser.paramCount,
+ shell->parser.param);
+ if (!command->attr.attrs.disableReturn)
+ {
+ shellWriteReturnValue(shell, returnValue);
+ }
+ }
+ else if (command->attr.attrs.type == SHELL_TYPE_CMD_FUNC)
+ {
+ returnValue = shellExtRun(shell,
+ command,
+ shell->parser.paramCount,
+ shell->parser.param);
+ if (!command->attr.attrs.disableReturn)
+ {
+ shellWriteReturnValue(shell, returnValue);
+ }
+ }
+ else if (command->attr.attrs.type >= SHELL_TYPE_VAR_INT
+ && command->attr.attrs.type <= SHELL_TYPE_VAR_NODE)
+ {
+ shellShowVar(shell, command);
+ }
+ else if (command->attr.attrs.type == SHELL_TYPE_USER)
+ {
+ shellSetUser(shell, command);
+ }
+ shell->status.isActive = 0;
+
+ return returnValue;
+}
+
+
+/**
+ * @brief shell校验密码
+ *
+ * @param shell shell对象
+ */
+static void shellCheckPassword(Shell *shell)
+{
+ if (strcmp(shell->parser.buffer, shell->info.user->data.user.password) == 0)
+ {
+ shell->status.isChecked = 1;
+ #if SHELL_SHOW_INFO == 1
+ shellWriteString(shell, shellText[SHELL_TEXT_INFO]);
+ #endif
+ }
+ else
+ {
+ shellWriteString(shell, shellText[SHELL_TEXT_PASSWORD_ERROR]);
+ }
+ shell->parser.length = 0;
+ shell->parser.cursor = 0;
+}
+
+
+/**
+ * @brief shell设置用户
+ *
+ * @param shell shell对象
+ * @param user 用户
+ */
+void shellSetUser(Shell *shell, const ShellCommand *user)
+{
+ shell->info.user = user;
+ shell->status.isChecked =
+ ((user->data.user.password && strlen(user->data.user.password) != 0)
+ && (shell->parser.paramCount < 2
+ || strcmp(user->data.user.password, shell->parser.param[1]) != 0))
+ ? 0 : 1;
+
+#if SHELL_CLS_WHEN_LOGIN == 1
+ shellWriteString(shell, shellText[SHELL_TEXT_CLEAR_CONSOLE]);
+#endif
+#if SHELL_SHOW_INFO == 1
+ if (shell->status.isChecked)
+ {
+ shellWriteString(shell, shellText[SHELL_TEXT_INFO]);
+ }
+#endif
+}
+
+
+/**
+ * @brief shell写返回值
+ *
+ * @param shell shell对象
+ * @param value 返回值
+ */
+static void shellWriteReturnValue(Shell *shell, int value)
+{
+ char buffer[12] = "00000000000";
+ shellWriteString(shell, "Return: ");
+ shellWriteString(shell, &buffer[11 - shellToDec(value, buffer)]);
+ shellWriteString(shell, ", 0x");
+ for (short i = 0; i < 11; i++)
+ {
+ buffer[i] = '0';
+ }
+ shellToHex(value, buffer);
+ shellWriteString(shell, buffer);
+ shellWriteString(shell, "\r\n");
+#if SHELL_KEEP_RETURN_VALUE == 1
+ shell->info.retVal = value;
+#endif
+}
+
+
+#if SHELL_HISTORY_MAX_NUMBER > 0
+/**
+ * @brief shell历史记录添加
+ *
+ * @param shell shell对象
+ */
+static void shellHistoryAdd(Shell *shell)
+{
+ shell->history.offset = 0;
+ if (shell->history.number > 0
+ && strcmp(shell->history.item[(shell->history.record == 0 ?
+ SHELL_HISTORY_MAX_NUMBER : shell->history.record) - 1],
+ shell->parser.buffer) == 0)
+ {
+ return;
+ }
+ if (shellStringCopy(shell->history.item[shell->history.record],
+ shell->parser.buffer) != 0)
+ {
+ shell->history.record++;
+ }
+ if (++shell->history.number > SHELL_HISTORY_MAX_NUMBER)
+ {
+ shell->history.number = SHELL_HISTORY_MAX_NUMBER;
+ }
+ if (shell->history.record >= SHELL_HISTORY_MAX_NUMBER)
+ {
+ shell->history.record = 0;
+ }
+}
+
+
+/**
+ * @brief shell历史记录查找
+ *
+ * @param shell shell对象
+ * @param dir 方向 {@code <0}往上查找 {@code >0}往下查找
+ */
+static void shellHistory(Shell *shell, signed char dir)
+{
+ if (dir > 0)
+ {
+ if (shell->history.offset-- <=
+ -((shell->history.number > shell->history.record) ?
+ shell->history.number : shell->history.record))
+ {
+ shell->history.offset = -((shell->history.number > shell->history.record)
+ ? shell->history.number : shell->history.record);
+ }
+ }
+ else if (dir < 0)
+ {
+ if (++shell->history.offset > 0)
+ {
+ shell->history.offset = 0;
+ return;
+ }
+ }
+ else
+ {
+ return;
+ }
+ shellClearCommandLine(shell);
+ if (shell->history.offset == 0)
+ {
+ shell->parser.cursor = shell->parser.length = 0;
+ }
+ else
+ {
+ if ((shell->parser.length = shellStringCopy(shell->parser.buffer,
+ shell->history.item[(shell->history.record + SHELL_HISTORY_MAX_NUMBER
+ + shell->history.offset) % SHELL_HISTORY_MAX_NUMBER])) == 0)
+ {
+ return;
+ }
+ shell->parser.cursor = shell->parser.length;
+ shellWriteString(shell, shell->parser.buffer);
+ }
+
+}
+#endif /** SHELL_HISTORY_MAX_NUMBER > 0 */
+
+
+/**
+ * @brief shell 常规输入
+ *
+ * @param shell shell 对象
+ * @param data 输入字符
+ */
+void shellNormalInput(Shell *shell, char data)
+{
+ shell->status.tabFlag = 0;
+ shellInsertByte(shell, data);
+}
+
+
+/**
+ * @brief shell运行命令
+ *
+ * @param shell shell对象
+ */
+void shellExec(Shell *shell)
+{
+
+ if (shell->parser.length == 0)
+ {
+ return;
+ }
+
+ shell->parser.buffer[shell->parser.length] = 0;
+
+ if (shell->status.isChecked)
+ {
+ #if SHELL_HISTORY_MAX_NUMBER > 0
+ shellHistoryAdd(shell);
+ #endif /** SHELL_HISTORY_MAX_NUMBER > 0 */
+ shellParserParam(shell);
+ shell->parser.length = shell->parser.cursor = 0;
+ if (shell->parser.paramCount == 0)
+ {
+ return;
+ }
+ shellWriteString(shell, "\r\n");
+
+ ShellCommand *command = shellSeekCommand(shell,
+ shell->parser.param[0],
+ shell->commandList.base,
+ 0);
+ if (command != NULL)
+ {
+ shellRunCommand(shell, command);
+ }
+ else
+ {
+ shellWriteString(shell, shellText[SHELL_TEXT_CMD_NOT_FOUND]);
+ }
+ }
+ else
+ {
+ shellCheckPassword(shell);
+ }
+}
+
+
+#if SHELL_HISTORY_MAX_NUMBER > 0
+/**
+ * @brief shell上方向键输入
+ *
+ * @param shell shell对象
+ */
+void shellUp(Shell *shell)
+{
+ shellHistory(shell, 1);
+}
+SHELL_EXPORT_KEY(SHELL_CMD_PERMISSION(0), 0x1B5B4100, shellUp, up);
+
+
+/**
+ * @brief shell下方向键输入
+ *
+ * @param shell shell对象
+ */
+void shellDown(Shell *shell)
+{
+ shellHistory(shell, -1);
+}
+SHELL_EXPORT_KEY(SHELL_CMD_PERMISSION(0), 0x1B5B4200, shellDown, down);
+#endif /** SHELL_HISTORY_MAX_NUMBER > 0 */
+
+
+/**
+ * @brief shell右方向键输入
+ *
+ * @param shell shell对象
+ */
+void shellRight(Shell *shell)
+{
+ if (shell->parser.cursor < shell->parser.length)
+ {
+ shellWriteByte(shell, shell->parser.buffer[shell->parser.cursor++]);
+ }
+}
+SHELL_EXPORT_KEY(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
+0x1B5B4300, shellRight, right);
+
+
+/**
+ * @brief shell左方向键输入
+ *
+ * @param shell shell对象
+ */
+void shellLeft(Shell *shell)
+{
+ if (shell->parser.cursor > 0)
+ {
+ shellWriteByte(shell, '\b');
+ shell->parser.cursor--;
+ }
+}
+SHELL_EXPORT_KEY(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
+0x1B5B4400, shellLeft, left);
+
+
+/**
+ * @brief shell Tab按键处理
+ *
+ * @param shell shell对象
+ */
+void shellTab(Shell *shell)
+{
+ unsigned short maxMatch = shell->parser.bufferSize;
+ unsigned short lastMatchIndex = 0;
+ unsigned short matchNum = 0;
+ unsigned short length;
+
+ if (shell->parser.length == 0)
+ {
+ shellListAll(shell);
+ shellWritePrompt(shell, 1);
+ }
+ else if (shell->parser.length > 0)
+ {
+ shell->parser.buffer[shell->parser.length] = 0;
+ ShellCommand *base = (ShellCommand *)shell->commandList.base;
+ for (short i = 0; i < shell->commandList.count; i++)
+ {
+ if (shellCheckPermission(shell, &base[i]) == 0
+ && shellStringCompare(shell->parser.buffer,
+ (char *)shellGetCommandName(&base[i]))
+ == shell->parser.length)
+ {
+ if (matchNum != 0)
+ {
+ if (matchNum == 1)
+ {
+ shellWriteString(shell, "\r\n");
+ }
+ shellListItem(shell, &base[lastMatchIndex]);
+ length =
+ shellStringCompare((char *)shellGetCommandName(&base[lastMatchIndex]),
+ (char *)shellGetCommandName(&base[i]));
+ maxMatch = (maxMatch > length) ? length : maxMatch;
+ }
+ lastMatchIndex = i;
+ matchNum++;
+ }
+ }
+ if (matchNum == 0)
+ {
+ return;
+ }
+ if (matchNum == 1)
+ {
+ shellClearCommandLine(shell);
+ }
+ if (matchNum != 0)
+ {
+ shell->parser.length =
+ shellStringCopy(shell->parser.buffer,
+ (char *)shellGetCommandName(&base[lastMatchIndex]));
+ }
+ if (matchNum > 1)
+ {
+ shellListItem(shell, &base[lastMatchIndex]);
+ shellWritePrompt(shell, 1);
+ shell->parser.length = maxMatch;
+ }
+ shell->parser.buffer[shell->parser.length] = 0;
+ shell->parser.cursor = shell->parser.length;
+ shellWriteString(shell, shell->parser.buffer);
+ }
+
+ if (SHELL_GET_TICK())
+ {
+ if (matchNum == 1
+ && shell->status.tabFlag
+ && SHELL_GET_TICK() - shell->info.activeTime < SHELL_DOUBLE_CLICK_TIME)
+ {
+ #if SHELL_QUICK_HELP == 1
+ shellWriteString(shell, "\r\n");
+ shellWriteCommandHelp(shell, shell->parser.buffer);
+ shellWritePrompt(shell, 1);
+ shellWriteString(shell, shell->parser.buffer);
+ #else
+ shellClearCommandLine(shell);
+ for (short i = shell->parser.length; i >= 0; i--)
+ {
+ shell->parser.buffer[i + 5] = shell->parser.buffer[i];
+ }
+ shellStringCopy(shell->parser.buffer, "help");
+ shell->parser.buffer[4] = ' ';
+ shell->parser.length += 5;
+ shell->parser.cursor = shell->parser.length;
+ shellWriteString(shell, shell->parser.buffer);
+ #endif
+ }
+ else
+ {
+ shell->status.tabFlag = 1;
+ }
+ }
+}
+SHELL_EXPORT_KEY(SHELL_CMD_PERMISSION(0), 0x09000000, shellTab, tab);
+
+
+/**
+ * @brief shell 退格
+ *
+ * @param shell shell对象
+ */
+void shellBackspace(Shell *shell)
+{
+ shellDeleteByte(shell, 1);
+}
+SHELL_EXPORT_KEY(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
+0x08000000, shellBackspace, backspace);
+SHELL_EXPORT_KEY(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
+0x7F000000, shellBackspace, backspace);
+
+
+/**
+ * @brief shell 删除
+ *
+ * @param shell shell对象
+ */
+void shellDelete(Shell *shell)
+{
+ shellDeleteByte(shell, -1);
+}
+SHELL_EXPORT_KEY(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
+0x1B5B337E, shellDelete, delete);
+
+
+/**
+ * @brief shell 回车处理
+ *
+ * @param shell shell对象
+ */
+void shellEnter(Shell *shell)
+{
+ shellExec(shell);
+ shellWritePrompt(shell, 1);
+}
+#if SHELL_ENTER_LF == 1
+SHELL_EXPORT_KEY(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
+0x0A000000, shellEnter, enter);
+#endif
+#if SHELL_ENTER_CR == 1
+SHELL_EXPORT_KEY(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
+0x0D000000, shellEnter, enter);
+#endif
+#if SHELL_ENTER_CRLF == 1
+SHELL_EXPORT_KEY(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
+0x0D0A0000, shellEnter, enter);
+#endif
+
+/**
+ * @brief shell 写命令帮助信息
+ *
+ * @param shell shell对象
+ * @param cmd 命令字符串
+ */
+static void shellWriteCommandHelp(Shell *shell, char *cmd)
+{
+ ShellCommand *command = shellSeekCommand(shell,
+ cmd,
+ shell->commandList.base,
+ 0);
+ if (command)
+ {
+ shellWriteString(shell, shellText[SHELL_TEXT_HELP_HEADER]);
+ shellWriteString(shell, shellGetCommandName(command));
+ shellWriteString(shell, "\r\n");
+ shellWriteString(shell, shellGetCommandDesc(command));
+ shellWriteString(shell, "\r\n");
+ }
+ else
+ {
+ shellWriteString(shell, shellText[SHELL_TEXT_CMD_NOT_FOUND]);
+ }
+}
+
+/**
+ * @brief shell help
+ *
+ * @param argc 参数个数
+ * @param argv 参数
+ */
+void shellHelp(int argc, char *argv[])
+{
+ Shell *shell = shellGetCurrent();
+ SHELL_ASSERT(shell, return);
+ if (argc == 1)
+ {
+ shellListAll(shell);
+ }
+ else if (argc > 1)
+ {
+ shellWriteCommandHelp(shell, argv[1]);
+ }
+}
+SHELL_EXPORT_CMD(
+SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN)|SHELL_CMD_DISABLE_RETURN,
+help, shellHelp, show command info\r\nhelp [cmd]);
+
+/**
+ * @brief shell 输入处理
+ *
+ * @param shell shell对象
+ * @param data 输入数据
+ */
+void shellHandler(Shell *shell, char data)
+{
+ SHELL_ASSERT(data, return);
+ SHELL_LOCK(shell);
+
+#if SHELL_LOCK_TIMEOUT > 0
+ if (shell->info.user->data.user.password
+ && strlen(shell->info.user->data.user.password) != 0
+ && SHELL_GET_TICK())
+ {
+ if (SHELL_GET_TICK() - shell->info.activeTime > SHELL_LOCK_TIMEOUT)
+ {
+ shell->status.isChecked = 0;
+ }
+ }
+#endif
+
+ /* 根据记录的按键键值计算当前字节在按键键值中的偏移 */
+ char keyByteOffset = 24;
+ int keyFilter = 0x00000000;
+ if ((shell->parser.keyValue & 0x0000FF00) != 0x00000000)
+ {
+ keyByteOffset = 0;
+ keyFilter = 0xFFFFFF00;
+ }
+ else if ((shell->parser.keyValue & 0x00FF0000) != 0x00000000)
+ {
+ keyByteOffset = 8;
+ keyFilter = 0xFFFF0000;
+ }
+ else if ((shell->parser.keyValue & 0xFF000000) != 0x00000000)
+ {
+ keyByteOffset = 16;
+ keyFilter = 0xFF000000;
+ }
+
+ /* 遍历ShellCommand列表,尝试进行按键键值匹配 */
+ ShellCommand *base = (ShellCommand *)shell->commandList.base;
+ for (short i = 0; i < shell->commandList.count; i++)
+ {
+ /* 判断是否是按键定义并验证权限 */
+ if (base[i].attr.attrs.type == SHELL_TYPE_KEY
+ && shellCheckPermission(shell, &(base[i])) == 0)
+ {
+ /* 对输入的字节同按键键值进行匹配 */
+ if ((base[i].data.key.value & keyFilter) == shell->parser.keyValue
+ && (base[i].data.key.value & (0xFF << keyByteOffset))
+ == (data << keyByteOffset))
+ {
+ shell->parser.keyValue |= data << keyByteOffset;
+ data = 0x00;
+ if (keyByteOffset == 0
+ || (base[i].data.key.value & (0xFF << (keyByteOffset - 8)))
+ == 0x00000000)
+ {
+ if (base[i].data.key.function)
+ {
+ base[i].data.key.function(shell);
+ }
+ shell->parser.keyValue = 0x00000000;
+ break;
+ }
+ }
+ }
+ }
+
+ if (data != 0x00)
+ {
+ shell->parser.keyValue = 0x00000000;
+ shellNormalInput(shell, data);
+ }
+
+ if (SHELL_GET_TICK())
+ {
+ shell->info.activeTime = SHELL_GET_TICK();
+ }
+ SHELL_UNLOCK(shell);
+}
+
+
+#if SHELL_SUPPORT_END_LINE == 1
+void shellWriteEndLine(Shell *shell, char *buffer, int len)
+{
+ SHELL_LOCK(shell);
+ if (!shell->status.isActive)
+ {
+ shellWriteString(shell, shellText[SHELL_TEXT_CLEAR_LINE]);
+ }
+ shell->write(buffer, len);
+
+ if (!shell->status.isActive)
+ {
+ shellWritePrompt(shell, 0);
+ if (shell->parser.length > 0)
+ {
+ shellWriteString(shell, shell->parser.buffer);
+ for (short i = 0; i < shell->parser.length - shell->parser.cursor; i++)
+ {
+ shellWriteByte(shell, '\b');
+ }
+ }
+ }
+ SHELL_UNLOCK(shell);
+}
+#endif /** SHELL_SUPPORT_END_LINE == 1 */
+
+
+/**
+ * @brief shell 任务
+ *
+ * @param param 参数(shell对象)
+ *
+ */
+void shellTask(void *param)
+{
+ Shell *shell = (Shell *)param;
+ char data;
+#if SHELL_TASK_WHILE == 1
+ while(1)
+ {
+#endif
+ if (shell->read && shell->read(&data, 1) == 1)
+ {
+ shellHandler(shell, data);
+ }
+#if SHELL_TASK_WHILE == 1
+ }
+#endif
+}
+
+
+/**
+ * @brief shell 输出用户列表(shell调用)
+ */
+void shellUsers(void)
+{
+ Shell *shell = shellGetCurrent();
+ if (shell)
+ {
+ shellListUser(shell);
+ }
+}
+SHELL_EXPORT_CMD(
+SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_DISABLE_RETURN,
+users, shellUsers, list all user);
+
+
+/**
+ * @brief shell 输出命令列表(shell调用)
+ */
+void shellCmds(void)
+{
+ Shell *shell = shellGetCurrent();
+ if (shell)
+ {
+ shellListCommand(shell);
+ }
+}
+SHELL_EXPORT_CMD(
+SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_DISABLE_RETURN,
+cmds, shellCmds, list all cmd);
+
+
+/**
+ * @brief shell 输出变量列表(shell调用)
+ */
+void shellVars(void)
+{
+ Shell *shell = shellGetCurrent();
+ if (shell)
+ {
+ shellListVar(shell);
+ }
+}
+SHELL_EXPORT_CMD(
+SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_DISABLE_RETURN,
+vars, shellVars, list all var);
+
+
+/**
+ * @brief shell 输出按键列表(shell调用)
+ */
+void shellKeys(void)
+{
+ Shell *shell = shellGetCurrent();
+ if (shell)
+ {
+ shellListKey(shell);
+ }
+}
+SHELL_EXPORT_CMD(
+SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_DISABLE_RETURN,
+keys, shellKeys, list all key);
+
+
+/**
+ * @brief shell 清空控制台(shell调用)
+ */
+void shellClear(void)
+{
+ Shell *shell = shellGetCurrent();
+ if (shell)
+ {
+ shellWriteString(shell, shellText[SHELL_TEXT_CLEAR_CONSOLE]);
+ }
+}
+SHELL_EXPORT_CMD(
+SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_DISABLE_RETURN,
+clear, shellClear, clear console);
+
+
+/**
+ * @brief shell执行命令
+ *
+ * @param shell shell对象
+ * @param cmd 命令字符串
+ * @return int 返回值
+ */
+int shellRun(Shell *shell, const char *cmd)
+{
+ SHELL_ASSERT(shell && cmd, return -1);
+ char active = shell->status.isActive;
+ if (strlen(cmd) > shell->parser.bufferSize - 1)
+ {
+ shellWriteString(shell, shellText[SHELL_TEXT_CMD_TOO_LONG]);
+ return -1;
+ }
+ else
+ {
+ shell->parser.length = shellStringCopy(shell->parser.buffer, (char *)cmd);
+ shellExec(shell);
+ shell->status.isActive = active;
+ return 0;
+ }
+}
+
+
+#if SHELL_EXEC_UNDEF_FUNC == 1
+/**
+ * @brief shell执行未定义函数
+ *
+ * @param argc 参数个数
+ * @param argv 参数
+ * @return int 返回值
+ */
+int shellExecute(int argc, char *argv[])
+{
+ Shell *shell = shellGetCurrent();
+ if (shell && argc >= 2)
+ {
+ int (*func)() = (int (*)())shellExtParsePara(shell, argv[1]);
+ ShellCommand command = {
+ .attr.value = SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)
+ |SHELL_CMD_DISABLE_RETURN,
+ .data.cmd.function = func,
+ };
+ return shellExtRun(shell, &command, argc - 1, &argv[1]);
+ }
+ else
+ {
+ shellWriteString(shell, shellText[SHELL_TEXT_PARAM_ERROR]);
+ return -1;
+ }
+}
+SHELL_EXPORT_CMD(
+SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN)|SHELL_CMD_DISABLE_RETURN,
+exec, shellExecute, execute function undefined);
+#endif
+
+#if SHELL_KEEP_RETURN_VALUE == 1
+/**
+ * @brief shell返回值获取
+ * 获取上一次执行的命令的返回值
+ *
+ * @return int 返回值
+ */
+static int shellRetValGet()
+{
+ Shell *shell = shellGetCurrent();
+ return shell ? shell->info.retVal : 0;
+}
+static ShellNodeVarAttr shellRetVal = {
+ .get = shellRetValGet
+};
+SHELL_EXPORT_VAR(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_VAR_NODE)|SHELL_CMD_READ_ONLY,
+RETVAL, &shellRetVal, return value of last command);
+#endif /** SHELL_KEEP_RETURN_VALUE == 1 */
+
+static void _prompt(int argc, char **argv)
+{
+ for (short i = 0; i < SHELL_MAX_NUMBER; i++)
+ {
+ if (shellList[i] != NULL)
+ {
+ shellWriteString(shellList[i], shellText[SHELL_TEXT_INFO]);
+ return;
+ }
+ }
+
+}
+
+SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), prompt, _prompt, show prompt info);
diff --git a/main/utilities/letter_shell/src/shell.h b/main/utilities/letter_shell/src/shell.h
new file mode 100644
index 0000000..c08bcc2
--- /dev/null
+++ b/main/utilities/letter_shell/src/shell.h
@@ -0,0 +1,472 @@
+/**
+ * @file shell.h
+ * @author Letter (NevermindZZT@gmail.com)
+ * @brief letter shell
+ * @version 3.0.0
+ * @date 2019-12-30
+ *
+ * @copyright (c) 2020 Letter
+ *
+ */
+
+#ifndef __SHELL_H__
+#define __SHELL_H__
+
+#include "shell_cfg.h"
+
+#define SHELL_VERSION "3.1.2" /**< 版本号 */
+
+
+/**
+ * @brief shell 断言
+ *
+ * @param expr 表达式
+ * @param action 断言失败操作
+ */
+#define SHELL_ASSERT(expr, action) \
+ if (!(expr)) { \
+ action; \
+ }
+
+#if SHELL_USING_LOCK == 1
+#define SHELL_LOCK(shell) shell->lock(shell)
+#define SHELL_UNLOCK(shell) shell->unlock(shell)
+#else
+#define SHELL_LOCK(shell)
+#define SHELL_UNLOCK(shell)
+#endif /** SHELL_USING_LOCK == 1 */
+/**
+ * @brief shell 命令权限
+ *
+ * @param permission 权限级别
+ */
+#define SHELL_CMD_PERMISSION(permission) \
+ (permission & 0x000000FF)
+
+/**
+ * @brief shell 命令类型
+ *
+ * @param type 类型
+ */
+#define SHELL_CMD_TYPE(type) \
+ ((type & 0x0000000F) << 8)
+
+/**
+ * @brief 使能命令在未校验密码的情况下使用
+ */
+#define SHELL_CMD_ENABLE_UNCHECKED \
+ (1 << 12)
+
+/**
+ * @brief 禁用返回值打印
+ */
+#define SHELL_CMD_DISABLE_RETURN \
+ (1 << 13)
+
+/**
+ * @brief 只读属性(仅对变量生效)
+ */
+#define SHELL_CMD_READ_ONLY \
+ (1 << 14)
+
+/**
+ * @brief 命令参数数量
+ */
+#define SHELL_CMD_PARAM_NUM(num) \
+ ((num & 0x0000000F)) << 16
+
+#ifndef SHELL_SECTION
+ #if defined(__CC_ARM) || defined(__CLANG_ARM)
+ #define SHELL_SECTION(x) __attribute__((section(x)))
+ #elif defined (__IAR_SYSTEMS_ICC__)
+ #define SHELL_SECTION(x) @ x
+ #elif defined(__GNUC__)
+ #define SHELL_SECTION(x) __attribute__((section(x)))
+ #else
+ #define SHELL_SECTION(x)
+ #endif
+#endif
+
+#ifndef SHELL_USED
+ #if defined(__CC_ARM) || defined(__CLANG_ARM)
+ #define SHELL_USED __attribute__((used))
+ #elif defined (__IAR_SYSTEMS_ICC__)
+ #define SHELL_USED __root
+ #elif defined(__GNUC__)
+ #define SHELL_USED __attribute__((used))
+ #else
+ #define SHELL_USED
+ #endif
+#endif
+
+/**
+ * @brief shell float型参数转换
+ */
+#define SHELL_PARAM_FLOAT(x) (*(float *)(&x))
+
+/**
+ * @brief shell 代理函数名
+ */
+#define SHELL_AGENCY_FUNC_NAME(_func) agency##_func
+
+/**
+ * @brief shell代理函数定义
+ *
+ * @param _func 被代理的函数
+ * @param ... 代理参数
+ */
+#define SHELL_AGENCY_FUNC(_func, ...) \
+ void SHELL_AGENCY_FUNC_NAME(_func)(int p1, int p2, int p3, int p4, int p5, int p6, int p7) \
+ { _func(__VA_ARGS__); }
+
+#if SHELL_USING_CMD_EXPORT == 1
+
+ /**
+ * @brief shell 命令定义
+ *
+ * @param _attr 命令属性
+ * @param _name 命令名
+ * @param _func 命令函数
+ * @param _desc 命令描述
+ */
+ #define SHELL_EXPORT_CMD(_attr, _name, _func, _desc) \
+ const char shellCmd##_name[] = #_name; \
+ const char shellDesc##_name[] = #_desc; \
+ SHELL_USED const ShellCommand \
+ shellCommand##_name SHELL_SECTION("shellCommand") = \
+ { \
+ .attr.value = _attr, \
+ .data.cmd.name = shellCmd##_name, \
+ .data.cmd.function = (int (*)())_func, \
+ .data.cmd.desc = shellDesc##_name \
+ }
+
+ /**
+ * @brief shell 代理命令定义
+ *
+ * @param _attr 命令属性
+ * @param _name 命令名
+ * @param _func 命令函数
+ * @param _desc 命令描述
+ * @param ... 代理参数
+ */
+ #define SHELL_EXPORT_CMD_AGENCY(_attr, _name, _func, _desc, ...) \
+ SHELL_AGENCY_FUNC(_func, ##__VA_ARGS__) \
+ SHELL_EXPORT_CMD(_attr, _name, SHELL_AGENCY_FUNC_NAME(_func), _desc)
+
+ /**
+ * @brief shell 变量定义
+ *
+ * @param _attr 变量属性
+ * @param _name 变量名
+ * @param _value 变量值
+ * @param _desc 变量描述
+ */
+ #define SHELL_EXPORT_VAR(_attr, _name, _value, _desc) \
+ const char shellCmd##_name[] = #_name; \
+ const char shellDesc##_name[] = #_desc; \
+ SHELL_USED const ShellCommand \
+ shellVar##_name SHELL_SECTION("shellCommand") = \
+ { \
+ .attr.value = _attr, \
+ .data.var.name = shellCmd##_name, \
+ .data.var.value = (void *)_value, \
+ .data.var.desc = shellDesc##_name \
+ }
+
+ /**
+ * @brief shell 用户定义
+ *
+ * @param _attr 用户属性
+ * @param _name 用户名
+ * @param _password 用户密码
+ * @param _desc 用户描述
+ */
+ #define SHELL_EXPORT_USER(_attr, _name, _password, _desc) \
+ const char shellCmd##_name[] = #_name; \
+ const char shellPassword##_name[] = #_password; \
+ const char shellDesc##_name[] = #_desc; \
+ SHELL_USED const ShellCommand \
+ shellUser##_name SHELL_SECTION("shellCommand") = \
+ { \
+ .attr.value = _attr|SHELL_CMD_TYPE(SHELL_TYPE_USER), \
+ .data.user.name = shellCmd##_name, \
+ .data.user.password = shellPassword##_name, \
+ .data.user.desc = shellDesc##_name \
+ }
+
+ /**
+ * @brief shell 按键定义
+ *
+ * @param _attr 按键属性
+ * @param _value 按键键值
+ * @param _func 按键函数
+ * @param _desc 按键描述
+ */
+ #define SHELL_EXPORT_KEY(_attr, _value, _func, _desc) \
+ const char shellDesc##_value[] = #_desc; \
+ SHELL_USED const ShellCommand \
+ shellKey##_value SHELL_SECTION("shellCommand") = \
+ { \
+ .attr.value = _attr|SHELL_CMD_TYPE(SHELL_TYPE_KEY), \
+ .data.key.value = _value, \
+ .data.key.function = (void (*)(Shell *))_func, \
+ .data.key.desc = shellDesc##_value \
+ }
+
+ /**
+ * @brief shell 代理按键定义
+ *
+ * @param _attr 按键属性
+ * @param _value 按键键值
+ * @param _func 按键函数
+ * @param _desc 按键描述
+ * @param ... 代理参数
+ */
+ #define SHELL_EXPORT_KEY_AGENCY(_attr, _value, _func, _desc, ...) \
+ SHELL_AGENCY_FUNC(_func, ##__VA_ARGS__) \
+ SHELL_EXPORT_KEY(_attr, _value, SHELL_AGENCY_FUNC_NAME(_func), _desc)
+#else
+ /**
+ * @brief shell 命令item定义
+ *
+ * @param _attr 命令属性
+ * @param _name 命令名
+ * @param _func 命令函数
+ * @param _desc 命令描述
+ */
+ #define SHELL_CMD_ITEM(_attr, _name, _func, _desc) \
+ { \
+ .attr.value = _attr, \
+ .data.cmd.name = #_name, \
+ .data.cmd.function = (int (*)())_func, \
+ .data.cmd.desc = #_desc \
+ }
+
+ /**
+ * @brief shell 变量item定义
+ *
+ * @param _attr 变量属性
+ * @param _name 变量名
+ * @param _value 变量值
+ * @param _desc 变量描述
+ */
+ #define SHELL_VAR_ITEM(_attr, _name, _value, _desc) \
+ { \
+ .attr.value = _attr, \
+ .data.var.name = #_name, \
+ .data.var.value = (void *)_value, \
+ .data.var.desc = #_desc \
+ }
+
+ /**
+ * @brief shell 用户item定义
+ *
+ * @param _attr 用户属性
+ * @param _name 用户名
+ * @param _password 用户密码
+ * @param _desc 用户描述
+ */
+ #define SHELL_USER_ITEM(_attr, _name, _password, _desc) \
+ { \
+ .attr.value = _attr|SHELL_CMD_TYPE(SHELL_TYPE_USER), \
+ .data.user.name = #_name, \
+ .data.user.password = #_password, \
+ .data.user.desc = #_desc \
+ }
+
+ /**
+ * @brief shell 按键item定义
+ *
+ * @param _attr 按键属性
+ * @param _value 按键键值
+ * @param _func 按键函数
+ * @param _desc 按键描述
+ */
+ #define SHELL_KEY_ITEM(_attr, _value, _func, _desc) \
+ { \
+ .attr.value = _attr|SHELL_CMD_TYPE(SHELL_TYPE_KEY), \
+ .data.key.value = _value, \
+ .data.key.function = (void (*)(Shell *))_func, \
+ .data.key.desc = #_desc \
+ }
+
+ #define SHELL_EXPORT_CMD(_attr, _name, _func, _desc)
+ #define SHELL_EXPORT_CMD_AGENCY(_attr, _name, _func, _desc, ...)
+ #define SHELL_EXPORT_VAR(_attr, _name, _value, _desc)
+ #define SHELL_EXPORT_USER(_attr, _name, _password, _desc)
+ #define SHELL_EXPORT_KEY(_attr, _value, _func, _desc)
+ #define SHELL_EXPORT_KEY_AGENCY(_attr, _name, _func, _desc, ...)
+#endif /** SHELL_USING_CMD_EXPORT == 1 */
+
+/**
+ * @brief shell command类型
+ */
+typedef enum
+{
+ SHELL_TYPE_CMD_MAIN = 0, /**< main形式命令 */
+ SHELL_TYPE_CMD_FUNC, /**< C函数形式命令 */
+ SHELL_TYPE_VAR_INT, /**< int型变量 */
+ SHELL_TYPE_VAR_SHORT, /**< short型变量 */
+ SHELL_TYPE_VAR_CHAR, /**< char型变量 */
+ SHELL_TYPE_VAR_STRING, /**< string型变量 */
+ SHELL_TYPE_VAR_POINT, /**< 指针型变量 */
+ SHELL_TYPE_VAR_NODE, /**< 节点变量 */
+ SHELL_TYPE_USER, /**< 用户 */
+ SHELL_TYPE_KEY, /**< 按键 */
+} ShellCommandType;
+
+
+/**
+ * @brief Shell定义
+ */
+typedef struct shell_def
+{
+ struct
+ {
+ const struct shell_command *user; /**< 当前用户 */
+ int activeTime; /**< shell激活时间 */
+ char *path; /**< 当前shell路径 */
+ #if SHELL_USING_COMPANION == 1
+ struct shell_companion_object *companions; /**< 伴生对象 */
+ #endif
+ #if SHELL_KEEP_RETURN_VALUE == 1
+ int retVal; /**< 返回值 */
+ #endif
+ } info;
+ struct
+ {
+ unsigned short length; /**< 输入数据长度 */
+ unsigned short cursor; /**< 当前光标位置 */
+ char *buffer; /**< 输入缓冲 */
+ char *param[SHELL_PARAMETER_MAX_NUMBER]; /**< 参数 */
+ unsigned short bufferSize; /**< 输入缓冲大小 */
+ unsigned short paramCount; /**< 参数数量 */
+ int keyValue; /**< 输入按键键值 */
+ } parser;
+#if SHELL_HISTORY_MAX_NUMBER > 0
+ struct
+ {
+ char *item[SHELL_HISTORY_MAX_NUMBER]; /**< 历史记录 */
+ unsigned short number; /**< 历史记录数 */
+ unsigned short record; /**< 当前记录位置 */
+ signed short offset; /**< 当前历史记录偏移 */
+ } history;
+#endif /** SHELL_HISTORY_MAX_NUMBER > 0 */
+ struct
+ {
+ void *base; /**< 命令表基址 */
+ unsigned short count; /**< 命令数量 */
+ } commandList;
+ struct
+ {
+ unsigned char isChecked : 1; /**< 密码校验通过 */
+ unsigned char isActive : 1; /**< 当前活动Shell */
+ unsigned char tabFlag : 1; /**< tab标志 */
+ } status;
+ signed short (*read)(char *, unsigned short); /**< shell读函数 */
+ signed short (*write)(char *, unsigned short); /**< shell写函数 */
+#if SHELL_USING_LOCK == 1
+ int (*lock)(struct shell_def *); /**< shell 加锁 */
+ int (*unlock)(struct shell_def *); /**< shell 解锁 */
+#endif
+} Shell;
+
+
+/**
+ * @brief shell command定义
+ */
+typedef struct shell_command
+{
+ union
+ {
+ struct
+ {
+ unsigned char permission : 8; /**< command权限 */
+ ShellCommandType type : 4; /**< command类型 */
+ unsigned char enableUnchecked : 1; /**< 在未校验密码的情况下可用 */
+ unsigned char disableReturn : 1; /**< 禁用返回值输出 */
+ unsigned char readOnly : 1; /**< 只读 */
+ unsigned char reserve : 1; /**< 保留 */
+ unsigned char paramNum : 4; /**< 参数数量 */
+ } attrs;
+ int value;
+ } attr; /**< 属性 */
+ union
+ {
+ struct
+ {
+ const char *name; /**< 命令名 */
+ int (*function)(); /**< 命令执行函数 */
+ const char *desc; /**< 命令描述 */
+ } cmd; /**< 命令定义 */
+ struct
+ {
+ const char *name; /**< 变量名 */
+ void *value; /**< 变量值 */
+ const char *desc; /**< 变量描述 */
+ } var; /**< 变量定义 */
+ struct
+ {
+ const char *name; /**< 用户名 */
+ const char *password; /**< 用户密码 */
+ const char *desc; /**< 用户描述 */
+ } user; /**< 用户定义 */
+ struct
+ {
+ int value; /**< 按键键值 */
+ void (*function)(Shell *); /**< 按键执行函数 */
+ const char *desc; /**< 按键描述 */
+ } key; /**< 按键定义 */
+ } data;
+} ShellCommand;
+
+/**
+ * @brief shell节点变量属性
+ */
+typedef struct
+{
+ void *var; /**< 变量引用 */
+ int (*get)(); /**< 变量get方法 */
+ int (*set)(); /**< 变量set方法 */
+} ShellNodeVarAttr;
+
+
+#define shellSetPath(_shell, _path) (_shell)->info.path = _path
+#define shellGetPath(_shell) ((_shell)->info.path)
+
+#define shellDeInit(shell) shellRemove(shell)
+
+void shellInit(Shell *shell, char *buffer, unsigned short size);
+void shellRemove(Shell *shell);
+unsigned short shellWriteString(Shell *shell, const char *string);
+void shellPrint(Shell *shell, const char *fmt, ...);
+void shellScan(Shell *shell, char *fmt, ...);
+Shell* shellGetCurrent(void);
+void shellHandler(Shell *shell, char data);
+void shellWriteEndLine(Shell *shell, char *buffer, int len);
+void shellTask(void *param);
+int shellRun(Shell *shell, const char *cmd);
+
+
+
+#if SHELL_USING_COMPANION == 1
+/**
+ * @brief shell伴生对象定义
+ */
+typedef struct shell_companion_object
+{
+ int id; /**< 伴生对象ID */
+ void *obj; /**< 伴生对象 */
+ struct shell_companion_object *next; /**< 下一个伴生对象 */
+} ShellCompanionObj;
+
+
+signed char shellCompanionAdd(Shell *shell, int id, void *object);
+signed char shellCompanionDel(Shell *shell, int id);
+void *shellCompanionGet(Shell *shell, int id);
+#endif
+
+#endif
+
+
diff --git a/main/utilities/letter_shell/src/shell_cfg.h b/main/utilities/letter_shell/src/shell_cfg.h
new file mode 100644
index 0000000..874043d
--- /dev/null
+++ b/main/utilities/letter_shell/src/shell_cfg.h
@@ -0,0 +1,188 @@
+/**
+ * @file shell_cfg.h
+ * @author Letter (nevermindzzt@gmail.com)
+ * @brief shell config
+ * @version 3.0.0
+ * @date 2019-12-31
+ *
+ * @copyright (c) 2019 Letter
+ *
+ */
+
+#ifndef __SHELL_CFG_H__
+#define __SHELL_CFG_H__
+
+
+/**
+ * @brief 是否使用默认shell任务while循环,使能宏`SHELL_USING_TASK`后此宏有意义
+ * 使能此宏,则`shellTask()`函数会一直循环读取输入,一般使用操作系统建立shell
+ * 任务时使能此宏,关闭此宏的情况下,一般适用于无操作系统,在主循环中调用`shellTask()`
+ */
+#define SHELL_TASK_WHILE 1
+
+/**
+ * @brief 是否使用命令导出方式
+ * 使能此宏后,可以使用`SHELL_EXPORT_CMD()`等导出命令
+ * 定义shell命令,关闭此宏的情况下,需要使用命令表的方式
+ */
+#define SHELL_USING_CMD_EXPORT 1
+
+/**
+ * @brief 是否使用shell伴生对象
+ * 一些扩展的组件(文件系统支持,日志工具等)需要使用伴生对象
+ */
+#define SHELL_USING_COMPANION 0
+
+/**
+ * @brief 支持shell尾行模式
+ */
+#define SHELL_SUPPORT_END_LINE 0
+
+/**
+ * @brief 是否在输出命令列表中列出用户
+ */
+#define SHELL_HELP_LIST_USER 0
+
+/**
+ * @brief 是否在输出命令列表中列出变量
+ */
+#define SHELL_HELP_LIST_VAR 0
+
+/**
+ * @brief 是否在输出命令列表中列出按键
+ */
+#define SHELL_HELP_LIST_KEY 0
+
+/**
+ * @brief 是否在输出命令列表中展示命令权限
+ */
+#define SHELL_HELP_SHOW_PERMISSION 1
+
+/**
+ * @brief 使用LF作为命令行回车触发
+ * 可以和SHELL_ENTER_CR同时开启
+ */
+#define SHELL_ENTER_LF 1
+
+/**
+ * @brief 使用CR作为命令行回车触发
+ * 可以和SHELL_ENTER_LF同时开启
+ */
+#define SHELL_ENTER_CR 1
+
+/**
+ * @brief 使用CRLF作为命令行回车触发
+ * 不可以和SHELL_ENTER_LF或SHELL_ENTER_CR同时开启
+ */
+#define SHELL_ENTER_CRLF 0
+
+/**
+ * @brief 使用执行未导出函数的功能
+ * 启用后,可以通过`exec [addr] [args]`直接执行对应地址的函数
+ * @attention 如果地址错误,可能会直接引起程序崩溃
+ */
+#define SHELL_EXEC_UNDEF_FUNC 0
+
+/**
+ * @brief shell命令参数最大数量
+ * 包含命令名在内,超过16个参数并且使用了参数自动转换的情况下,需要修改源码
+ */
+#define SHELL_PARAMETER_MAX_NUMBER 8
+
+/**
+ * @brief 历史命令记录数量
+ */
+#define SHELL_HISTORY_MAX_NUMBER 5
+
+/**
+ * @brief 双击间隔(ms)
+ * 使能宏`SHELL_LONG_HELP`后此宏生效,定义双击tab补全help的时间间隔
+ */
+#define SHELL_DOUBLE_CLICK_TIME 200
+
+/**
+ * @brief 快速帮助
+ * 作用于双击tab的场景,当使能此宏时,双击tab不会对命令进行help补全,而是直接显示对应命令的帮助信息
+ */
+#define SHELL_QUICK_HELP 1
+
+/**
+ * @brief 保存命令返回值
+ * 开启后会默认定义一个`RETVAL`变量,会保存上一次命令执行的返回值,可以在随后的命令中进行调用
+ * 如果命令的`SHELL_CMD_DISABLE_RETURN`标志被设置,则该命令不会更新`RETVAL`
+ */
+#define SHELL_KEEP_RETURN_VALUE 0
+
+/**
+ * @brief 管理的最大shell数量
+ */
+#define SHELL_MAX_NUMBER 5
+
+/**
+ * @brief shell格式化输出的缓冲大小
+ * 为0时不使用shell格式化输出
+ */
+#define SHELL_PRINT_BUFFER 128
+
+/**
+ * @brief shell格式化输入的缓冲大小
+ * 为0时不使用shell格式化输入
+ * @note shell格式化输入会阻塞shellTask, 仅适用于在有操作系统的情况下使用
+ */
+#define SHELL_SCAN_BUFFER 0
+
+/**
+ * @brief 获取系统时间(ms)
+ * 定义此宏为获取系统Tick,如`HAL_GetTick()`
+ * @note 此宏不定义时无法使用双击tab补全命令help,无法使用shell超时锁定
+ */
+#define SHELL_GET_TICK() 0
+
+/**
+ * @brief 使用锁
+ * @note 使用shell锁时,需要对加锁和解锁进行实现
+ */
+#define SHELL_USING_LOCK 0
+
+/**
+ * @brief shell内存分配
+ * shell本身不需要此接口,若使用shell伴生对象,需要进行定义
+ */
+#define SHELL_MALLOC(size) 0
+
+/**
+ * @brief shell内存释放
+ * shell本身不需要此接口,若使用shell伴生对象,需要进行定义
+ */
+#define SHELL_FREE(obj) 0
+
+/**
+ * @brief 是否显示shell信息
+ */
+#define SHELL_SHOW_INFO 1
+
+/**
+ * @brief 是否在登录后清除命令行
+ */
+#define SHELL_CLS_WHEN_LOGIN 1
+
+/**
+ * @brief shell默认用户
+ */
+#define SHELL_DEFAULT_USER "letter"
+
+/**
+ * @brief shell默认用户密码
+ * 若默认用户不需要密码,设为""
+ */
+#define SHELL_DEFAULT_USER_PASSWORD ""
+
+/**
+ * @brief shell自动锁定超时
+ * shell当前用户密码有效的时候生效,超时后会自动重新锁定shell
+ * 设置为0时关闭自动锁定功能,时间单位为`SHELL_GET_TICK()`单位
+ * @note 使用超时锁定必须保证`SHELL_GET_TICK()`有效
+ */
+#define SHELL_LOCK_TIMEOUT 0 * 60 * 1000
+
+#endif
diff --git a/main/utilities/letter_shell/src/shell_cmd_list.c b/main/utilities/letter_shell/src/shell_cmd_list.c
new file mode 100644
index 0000000..139a531
--- /dev/null
+++ b/main/utilities/letter_shell/src/shell_cmd_list.c
@@ -0,0 +1,103 @@
+/**
+ * @file shell_cmd_list.c
+ * @author Letter (NevermindZZT@gmail.com)
+ * @brief shell cmd list
+ * @version 3.0.0
+ * @date 2020-01-17
+ *
+ * @copyright (c) 2020 Letter
+ *
+ */
+
+#include "shell.h"
+
+#if SHELL_USING_CMD_EXPORT != 1
+
+extern int shellSetVar(char *name, int value);
+extern void shellUp(Shell *shell);
+extern void shellDown(Shell *shell);
+extern void shellRight(Shell *shell);
+extern void shellLeft(Shell *shell);
+extern void shellTab(Shell *shell);
+extern void shellBackspace(Shell *shell);
+extern void shellDelete(Shell *shell);
+extern void shellEnter(Shell *shell);
+extern void shellHelp(int argc, char *argv[]);
+extern void shellUsers(void);
+extern void shellCmds(void);
+extern void shellVars(void);
+extern void shellKeys(void);
+extern void shellClear(void);
+#if SHELL_EXEC_UNDEF_FUNC == 1
+extern int shellExecute(int argc, char *argv[]);
+#endif
+
+SHELL_AGENCY_FUNC(shellRun, shellGetCurrent(), (const char *)p1);
+
+
+/**
+ * @brief shell命令表
+ *
+ */
+const ShellCommand shellCommandList[] =
+{
+ {.attr.value=SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_USER),
+ .data.user.name = SHELL_DEFAULT_USER,
+ .data.user.password = SHELL_DEFAULT_USER_PASSWORD,
+ .data.user.desc = "default user"},
+ SHELL_CMD_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC),
+ setVar, shellSetVar, set var),
+ SHELL_KEY_ITEM(SHELL_CMD_PERMISSION(0), 0x1B5B4100, shellUp, up),
+ SHELL_KEY_ITEM(SHELL_CMD_PERMISSION(0), 0x1B5B4200, shellDown, down),
+ SHELL_KEY_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
+ 0x1B5B4300, shellRight, right),
+ SHELL_KEY_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
+ 0x1B5B4400, shellLeft, left),
+ SHELL_KEY_ITEM(SHELL_CMD_PERMISSION(0), 0x09000000, shellTab, tab),
+ SHELL_KEY_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
+ 0x08000000, shellBackspace, backspace),
+ SHELL_KEY_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
+ 0x7F000000, shellDelete, delete),
+ SHELL_KEY_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
+ 0x1B5B337E, shellDelete, delete),
+#if SHELL_ENTER_LF == 1
+ SHELL_KEY_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
+ 0x0A000000, shellEnter, enter),
+#endif
+#if SHELL_ENTER_CR == 1
+ SHELL_KEY_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
+ 0x0D000000, shellEnter, enter),
+#endif
+#if SHELL_ENTER_CRLF == 1
+ SHELL_KEY_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_ENABLE_UNCHECKED,
+ 0x0D0A0000, shellEnter, enter),
+#endif
+ SHELL_CMD_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN)|SHELL_CMD_DISABLE_RETURN,
+ help, shellHelp, show command info\r\nhelp [cmd]),
+ SHELL_CMD_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_DISABLE_RETURN,
+ users, shellUsers, list all user),
+ SHELL_CMD_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_DISABLE_RETURN,
+ cmds, shellCmds, list all cmd),
+ SHELL_CMD_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_DISABLE_RETURN,
+ vars, shellVars, list all var),
+ SHELL_CMD_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_DISABLE_RETURN,
+ keys, shellKeys, list all key),
+ SHELL_CMD_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_DISABLE_RETURN,
+ clear, shellClear, clear console),
+ SHELL_CMD_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_DISABLE_RETURN,
+ sh, SHELL_AGENCY_FUNC_NAME(shellRun), run command directly),
+#if SHELL_EXEC_UNDEF_FUNC == 1
+ SHELL_CMD_ITEM(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN)|SHELL_CMD_DISABLE_RETURN,
+ exec, shellExecute, execute function undefined),
+#endif
+};
+
+
+/**
+ * @brief shell命令表大小
+ *
+ */
+const unsigned short shellCommandCount
+ = sizeof(shellCommandList) / sizeof(ShellCommand);
+
+#endif
diff --git a/main/utilities/letter_shell/src/shell_companion.c b/main/utilities/letter_shell/src/shell_companion.c
new file mode 100644
index 0000000..eb494c7
--- /dev/null
+++ b/main/utilities/letter_shell/src/shell_companion.c
@@ -0,0 +1,87 @@
+/**
+ * @file shell_companion.c
+ * @author Letter (nevermindzzt@gmail.com)
+ * @brief shell companion object support
+ * @version 3.0.3
+ * @date 2020-07-22
+ *
+ * @copyright (c) 2020 Letter
+ *
+ */
+ #include "shell.h"
+
+#if SHELL_USING_COMPANION == 1
+/**
+ * @brief shell添加伴生对象
+ *
+ * @param shell shell对象
+ * @param id 伴生对象ID
+ * @param object 伴生对象
+ * @return signed char 0 添加成功 -1 添加失败
+ */
+signed char shellCompanionAdd(Shell *shell, int id, void *object)
+{
+ ShellCompanionObj *companions = shell->info.companions;
+ ShellCompanionObj *node = SHELL_MALLOC(sizeof(ShellCompanionObj));
+ SHELL_ASSERT(node, return -1);
+ node->id = id;
+ node->obj = object;
+ node->next = companions;
+ shell->info.companions = node;
+ return 0;
+}
+
+/**
+ * @brief shell删除伴生对象
+ *
+ * @param shell shell对象
+ * @param id 伴生对象ID
+ * @return signed char 0 删除成功 -1 无匹配对象
+ */
+signed char shellCompanionDel(Shell *shell, int id)
+{
+ ShellCompanionObj *companions = shell->info.companions;
+ ShellCompanionObj *front = companions;
+ while (companions)
+ {
+ if (companions->id == id)
+ {
+ if (companions == shell->info.companions && !(companions->next))
+ {
+ shell->info.companions = (void *)0;
+ }
+ else
+ {
+ front->next = companions->next;
+ }
+ SHELL_FREE(companions);
+ return 0;
+ }
+ front = companions;
+ companions = companions->next;
+ }
+ return -1;
+}
+
+/**
+ * @brief shell获取伴生对象
+ *
+ * @param shell shell对象
+ * @param id 伴生对象ID
+ * @return void* 伴生对象,无匹配对象时返回NULL
+ */
+void *shellCompanionGet(Shell *shell, int id)
+{
+ SHELL_ASSERT(shell, return (void *)0);
+ ShellCompanionObj *companions = shell->info.companions;
+ while (companions)
+ {
+ if (companions->id == id)
+ {
+ return companions->obj;
+ }
+ companions = companions->next;
+ }
+ return (void *)0;
+}
+#endif /** SHELL_USING_COMPANION == 1 */
diff --git a/main/utilities/letter_shell/src/shell_ext.c b/main/utilities/letter_shell/src/shell_ext.c
new file mode 100644
index 0000000..7fbbc61
--- /dev/null
+++ b/main/utilities/letter_shell/src/shell_ext.c
@@ -0,0 +1,447 @@
+/**
+ * @file shell_ext.c
+ * @author Letter (NevermindZZT@gmail.com)
+ * @brief shell extensions
+ * @version 3.0.0
+ * @date 2019-12-31
+ *
+ * @copyright (c) 2019 Letter
+ *
+ */
+
+#include "shell_cfg.h"
+#include "shell.h"
+#include "shell_ext.h"
+
+
+extern ShellCommand* shellSeekCommand(Shell *shell,
+ const char *cmd,
+ ShellCommand *base,
+ unsigned short compareLength);
+extern int shellGetVarValue(Shell *shell, ShellCommand *command);
+
+/**
+ * @brief 判断数字进制
+ *
+ * @param string 参数字符串
+ * @return ShellNumType 进制
+ */
+static ShellNumType shellExtNumType(char *string)
+{
+ char *p = string;
+ ShellNumType type = NUM_TYPE_DEC;
+
+ if ((*p == '0') && ((*(p + 1) == 'x') || (*(p + 1) == 'X')))
+ {
+ type = NUM_TYPE_HEX;
+ }
+ else if ((*p == '0') && ((*(p + 1) == 'b') || (*(p + 1) == 'B')))
+ {
+ type = NUM_TYPE_BIN;
+ }
+ else if (*p == '0')
+ {
+ type = NUM_TYPE_OCT;
+ }
+
+ while (*p++)
+ {
+ if (*p == '.' && *(p + 1) != 0)
+ {
+ type = NUM_TYPE_FLOAT;
+ break;
+ }
+ }
+
+ return type;
+}
+
+
+/**
+ * @brief 字符转数字
+ *
+ * @param code 字符
+ * @return char 数字
+ */
+static char shellExtToNum(char code)
+{
+ if ((code >= '0') && (code <= '9'))
+ {
+ return code -'0';
+ }
+ else if ((code >= 'a') && (code <= 'f'))
+ {
+ return code - 'a' + 10;
+ }
+ else if ((code >= 'A') && (code <= 'F'))
+ {
+ return code - 'A' + 10;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+
+/**
+ * @brief 解析字符参数
+ *
+ * @param string 字符串参数
+ * @return char 解析出的字符
+ */
+static char shellExtParseChar(char *string)
+{
+ char *p = string + 1;
+ char value = 0;
+
+ if (*p == '\\')
+ {
+ switch (*(p + 1))
+ {
+ case 'b':
+ value = '\b';
+ break;
+ case 'r':
+ value = '\r';
+ break;
+ case 'n':
+ value = '\n';
+ break;
+ case 't':
+ value = '\t';
+ break;
+ case '0':
+ value = 0;
+ break;
+ default:
+ value = *(p + 1);
+ break;
+ }
+ }
+ else
+ {
+ value = *p;
+ }
+ return value;
+}
+
+
+/**
+ * @brief 解析字符串参数
+ *
+ * @param string 字符串参数
+ * @return char* 解析出的字符串
+ */
+static char* shellExtParseString(char *string)
+{
+ char *p = string;
+ unsigned short index = 0;
+
+ if (*string == '\"')
+ {
+ p = ++string;
+ }
+
+ while (*p)
+ {
+ if (*p == '\\')
+ {
+ *(string + index) = shellExtParseChar(p - 1);
+ p++;
+ }
+ else if (*p == '\"')
+ {
+ *(string + index) = 0;
+ }
+ else
+ {
+ *(string + index) = *p;
+ }
+ p++;
+ index ++;
+ }
+ *(string + index) = 0;
+ return string;
+}
+
+
+/**
+ * @brief 解析数字参数
+ *
+ * @param string 字符串参数
+ * @return unsigned int 解析出的数字
+ */
+static unsigned int shellExtParseNumber(char *string)
+{
+ ShellNumType type = NUM_TYPE_DEC;
+ char radix = 10;
+ char *p = string;
+ char offset = 0;
+ signed char sign = 1;
+ unsigned int valueInt = 0;
+ float valueFloat = 0.0;
+ unsigned int devide = 0;
+
+ if (*string == '-')
+ {
+ sign = -1;
+ }
+
+ type = shellExtNumType(string + ((sign == -1) ? 1 : 0));
+
+ switch ((char)type)
+ {
+ case NUM_TYPE_HEX:
+ radix = 16;
+ offset = 2;
+ break;
+
+ case NUM_TYPE_OCT:
+ radix = 8;
+ offset = 1;
+ break;
+
+ case NUM_TYPE_BIN:
+ radix = 2;
+ offset = 2;
+ break;
+
+ default:
+ break;
+ }
+
+ p = string + offset + ((sign == -1) ? 1 : 0);
+
+ while (*p)
+ {
+ if (*p == '.')
+ {
+ devide = 1;
+ p++;
+ continue;
+ }
+ valueInt = valueInt * radix + shellExtToNum(*p);
+ devide *= 10;
+ p++;
+ }
+ if (type == NUM_TYPE_FLOAT && devide != 0)
+ {
+ valueFloat = (float)valueInt / devide * sign;
+ return *(unsigned int *)(&valueFloat);
+ }
+ else
+ {
+ return valueInt * sign;
+ }
+}
+
+
+/**
+ * @brief 解析变量参数
+ *
+ * @param shell shell对象
+ * @param var 变量
+ * @return unsigned int 变量值
+ */
+static unsigned int shellExtParseVar(Shell *shell, char *var)
+{
+ ShellCommand *command = shellSeekCommand(shell,
+ var + 1,
+ shell->commandList.base,
+ 0);
+ if (command)
+ {
+ return shellGetVarValue(shell, command);
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+
+/**
+ * @brief 解析参数
+ *
+ * @param shell shell对象
+ * @param string 参数
+ * @return unsigned int 解析结果
+ */
+unsigned int shellExtParsePara(Shell *shell, char *string)
+{
+ if (*string == '\'' && *(string + 1))
+ {
+ return (unsigned int)shellExtParseChar(string);
+ }
+ else if (*string == '-' || (*string >= '0' && *string <= '9'))
+ {
+ return (unsigned int)shellExtParseNumber(string);
+ }
+ else if (*string == '$' && *(string + 1))
+ {
+ return shellExtParseVar(shell, string);
+ }
+ else if (*string)
+ {
+ return (unsigned int)shellExtParseString(string);
+ }
+ return 0;
+}
+
+
+/**
+ * @brief 执行命令
+ *
+ * @param shell shell对象
+ * @param command 命令
+ * @param argc 参数个数
+ * @param argv 参数
+ * @return int 返回值
+ */
+int shellExtRun(Shell *shell, ShellCommand *command, int argc, char *argv[])
+{
+ unsigned int params[SHELL_PARAMETER_MAX_NUMBER] = {0};
+ int paramNum = command->attr.attrs.paramNum > (argc - 1) ?
+ command->attr.attrs.paramNum : (argc - 1);
+ for (int i = 0; i < argc - 1; i++)
+ {
+ params[i] = shellExtParsePara(shell, argv[i + 1]);
+ }
+ switch (paramNum)
+ {
+#if SHELL_PARAMETER_MAX_NUMBER >= 1
+ case 0:
+ return command->data.cmd.function();
+ // break;
+#endif /** SHELL_PARAMETER_MAX_NUMBER >= 1 */
+#if SHELL_PARAMETER_MAX_NUMBER >= 2
+ case 1:
+ return command->data.cmd.function(params[0]);
+ // break;
+#endif /** SHELL_PARAMETER_MAX_NUMBER >= 2 */
+#if SHELL_PARAMETER_MAX_NUMBER >= 3
+ case 2:
+ return command->data.cmd.function(params[0], params[1]);
+ // break;
+#endif /** SHELL_PARAMETER_MAX_NUMBER >= 3 */
+#if SHELL_PARAMETER_MAX_NUMBER >= 4
+ case 3:
+ return command->data.cmd.function(params[0], params[1],
+ params[2]);
+ // break;
+#endif /** SHELL_PARAMETER_MAX_NUMBER >= 4 */
+#if SHELL_PARAMETER_MAX_NUMBER >= 5
+ case 4:
+ return command->data.cmd.function(params[0], params[1],
+ params[2], params[3]);
+ // break;
+#endif /** SHELL_PARAMETER_MAX_NUMBER >= 5 */
+#if SHELL_PARAMETER_MAX_NUMBER >= 6
+ case 5:
+ return command->data.cmd.function(params[0], params[1],
+ params[2], params[3],
+ params[4]);
+ // break;
+#endif /** SHELL_PARAMETER_MAX_NUMBER >= 6 */
+#if SHELL_PARAMETER_MAX_NUMBER >= 7
+ case 6:
+ return command->data.cmd.function(params[0], params[1],
+ params[2], params[3],
+ params[4], params[5]);
+ // break;
+#endif /** SHELL_PARAMETER_MAX_NUMBER >= 7 */
+#if SHELL_PARAMETER_MAX_NUMBER >= 8
+ case 7:
+ return command->data.cmd.function(params[0], params[1],
+ params[2], params[3],
+ params[4], params[5],
+ params[6]);
+ // break;
+#endif /** SHELL_PARAMETER_MAX_NUMBER >= 8 */
+#if SHELL_PARAMETER_MAX_NUMBER >= 9
+ case 8:
+ return command->data.cmd.function(params[0], params[1],
+ params[2], params[3],
+ params[4], params[5],
+ params[6], params[7]);
+ // break;
+#endif /** SHELL_PARAMETER_MAX_NUMBER >= 9 */
+#if SHELL_PARAMETER_MAX_NUMBER >= 10
+ case 9:
+ return command->data.cmd.function(params[0], params[1],
+ params[2], params[3],
+ params[4], params[5],
+ params[6], params[7],
+ params[8]);
+ // break;
+#endif /** SHELL_PARAMETER_MAX_NUMBER >= 10 */
+#if SHELL_PARAMETER_MAX_NUMBER >= 11
+ case 10:
+ return command->data.cmd.function(params[0], params[1],
+ params[2], params[3],
+ params[4], params[5],
+ params[6], params[7],
+ params[8], params[9]);
+ // break;
+#endif /** SHELL_PARAMETER_MAX_NUMBER >= 11 */
+#if SHELL_PARAMETER_MAX_NUMBER >= 12
+ case 11:
+ return command->data.cmd.function(params[0], params[1],
+ params[2], params[3],
+ params[4], params[5],
+ params[6], params[7],
+ params[8], params[9],
+ params[10]);
+ // break;
+#endif /** SHELL_PARAMETER_MAX_NUMBER >= 12 */
+#if SHELL_PARAMETER_MAX_NUMBER >= 13
+ case 12:
+ return command->data.cmd.function(params[0], params[1],
+ params[2], params[3],
+ params[4], params[5],
+ params[6], params[7],
+ params[8], params[9],
+ params[10], params[11]);
+ // break;
+#endif /** SHELL_PARAMETER_MAX_NUMBER >= 13 */
+#if SHELL_PARAMETER_MAX_NUMBER >= 14
+ case 13:
+ return command->data.cmd.function(params[0], params[1],
+ params[2], params[3],
+ params[4], params[5],
+ params[6], params[7],
+ params[8], params[9],
+ params[10], params[11],
+ params[12]);
+ // break;
+#endif /** SHELL_PARAMETER_MAX_NUMBER >= 14 */
+#if SHELL_PARAMETER_MAX_NUMBER >= 15
+ case 14:
+ return command->data.cmd.function(params[0], params[1],
+ params[2], params[3],
+ params[4], params[5],
+ params[6], params[7],
+ params[8], params[9],
+ params[10], params[11],
+ params[12], params[13]);
+ // break;
+#endif /** SHELL_PARAMETER_MAX_NUMBER >= 15 */
+#if SHELL_PARAMETER_MAX_NUMBER >= 16
+ case 15:
+ return command->data.cmd.function(params[0], params[1],
+ params[2], params[3],
+ params[4], params[5],
+ params[6], params[7],
+ params[8], params[9],
+ params[10], params[11],
+ params[12], params[13],
+ params[14]);
+ // break;
+#endif /** SHELL_PARAMETER_MAX_NUMBER >= 16 */
+ default:
+ return -1;
+ // break;
+ }
+}
+
diff --git a/main/utilities/letter_shell/src/shell_ext.h b/main/utilities/letter_shell/src/shell_ext.h
new file mode 100644
index 0000000..2e6158c
--- /dev/null
+++ b/main/utilities/letter_shell/src/shell_ext.h
@@ -0,0 +1,33 @@
+/**
+ * @file shell_ext.h
+ * @author Letter (NevermindZZT@gmail.com)
+ * @brief shell extensions
+ * @version 3.0.0
+ * @date 2019-12-31
+ *
+ * @copyright (c) 2019 Letter
+ *
+ */
+
+#ifndef __SHELL_EXT_H__
+#define __SHELL_EXT_H__
+
+#include "shell.h"
+
+/**
+ * @brief 数字类型
+ *
+ */
+typedef enum
+{
+ NUM_TYPE_DEC, /**< 十进制整型 */
+ NUM_TYPE_BIN, /**< 二进制整型 */
+ NUM_TYPE_OCT, /**< 八进制整型 */
+ NUM_TYPE_HEX, /**< 十六进制整型 */
+ NUM_TYPE_FLOAT /**< 浮点型 */
+} ShellNumType;
+
+unsigned int shellExtParsePara(Shell *shell, char *string);
+int shellExtRun(Shell *shell, ShellCommand *command, int argc, char *argv[]);
+
+#endif
diff --git a/main/utilities/link_list/link_list.c b/main/utilities/link_list/link_list.c
new file mode 100644
index 0000000..22f1afa
--- /dev/null
+++ b/main/utilities/link_list/link_list.c
@@ -0,0 +1,144 @@
+/**
+ * @file link_list.c
+ * @author impressionyang (impressionyang@outlook.com)
+ * @brief
+ * @version 0.1
+ * @date 2022-10-12
+ * _ _
+ * (_)_ _ ___ _______ ___ ___ (_)__ ___ __ _____ ____ ___ _
+ * / / ' \/ _ \/ __/ -_|_-<(_- / _ \/ _ \/ // / _ `/ _ \/ _ `/
+ * /_/_/_/_/ .__/_/ \__/___/___/_/\___/_//_/\_, /\_,_/_//_/\_, /
+ * /_/ /___/ /___/
+ * @copyright Copyright (c) 2022 impressionyang
+ *
+ * @par 修改日志:
+ *
+ * | Date | Version | Author | Description
+ * |
|---|
| 2022-10-12 | v1.0 | impressionyang | 内容
+ * |
+ */
+#include "link_list.h"
+#include
+#include
+
+static uint8_t sg_link_list_node_id = 0;
+
+link_list_handle_t* link_list_init()
+{
+ link_list_handle_t *ptr = (link_list_handle_t *)malloc(sizeof(link_list_handle_t));
+
+ ptr->link_list_length = 0;
+ ptr->link_list_header = NULL;
+ ptr->link_list_tail = NULL;
+
+ return ptr;
+}
+uint8_t link_list_append_node_to_tail(link_list_handle_t *link_list, void *node_data_ptr, uint8_t *node_id)
+{
+ link_list_node_t *node = (link_list_node_t *)malloc(sizeof(link_list_node_t));
+
+ if (!link_list || !node_data_ptr || !node_id) {
+ // null pointer error
+ return 1;
+ }
+
+ node->node_id = sg_link_list_node_id++;
+ node->node_data_ptr = node_data_ptr;
+ node->next = NULL;
+
+ if (NULL == link_list->link_list_header) {
+ link_list->link_list_header = node;
+ link_list->link_list_tail = node;
+ }else {
+ link_list->link_list_tail->next = node;
+ link_list->link_list_tail = node;
+ }
+
+ return 0;
+}
+
+link_list_node_t *link_list_get_next_node(link_list_handle_t *link_list, link_list_node_t *node, void *node_data_ptr)
+{
+ if (!link_list || !node_data_ptr || !node) {
+ // null pointer error
+ return NULL;
+ }
+
+ return node->next;
+}
+
+uint8_t link_list_get_node_by_id(link_list_handle_t *link_list, void *node_data_ptr, uint8_t node_id)
+{
+ link_list_node_t *head = link_list->link_list_header;
+ link_list_node_t *p, *q;
+
+ if (!link_list || !node_data_ptr ) {
+ // null pointer error
+ return 1;
+ }
+
+ if (node_id > link_list->link_list_length) {
+ // id error
+ return 2;
+ }
+
+ for (p = head; p->next != NULL; p = p->next) {
+ if (p->node_id == node_id) {
+ node_data_ptr = p->node_data_ptr;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+uint8_t link_list_delete_node_by_id(link_list_handle_t *link_list, uint8_t node_id)
+{
+ link_list_node_t *head = link_list->link_list_header;
+ link_list_node_t *p, *q;
+
+ if (!link_list ) {
+ // null pointer error
+ return 1;
+ }
+
+ if (node_id > link_list->link_list_length) {
+ // id error
+ return 2;
+ }
+
+ q = head;
+ for (p = head; p->next != NULL; p = p->next) {
+ if (p->node_id == node_id) {
+ q->next = p->next;
+ if (p == link_list->link_list_tail) {
+ link_list->link_list_tail = q;
+ }
+ free(p);
+ break;
+ }
+ q = p;
+ }
+
+ return 0;
+}
+
+uint8_t link_list_deinit(link_list_handle_t* link_list)
+{
+ if (!link_list) {
+ // null pointer
+ return 1;
+ }
+
+ link_list_node_t *head = link_list->link_list_header;
+ link_list_node_t *p, *q;
+
+ for (p = head; p->next != NULL; p = q) {
+ q = p->next;
+ free(p);
+ }
+
+ free (link_list);
+
+ return 0;
+}
\ No newline at end of file
diff --git a/main/utilities/link_list/link_list.h b/main/utilities/link_list/link_list.h
new file mode 100644
index 0000000..2c4816d
--- /dev/null
+++ b/main/utilities/link_list/link_list.h
@@ -0,0 +1,128 @@
+/**
+ * @file link_list.h
+ * @author impressionyang (impressionyang@outlook.com)
+ * @brief 链表的数据结构
+ * @version 0.1
+ * @date 2022-10-12
+ * _ _
+ * (_)_ _ ___ _______ ___ ___ (_)__ ___ __ _____ ____ ___ _
+ * / / ' \/ _ \/ __/ -_|_-<(_- / _ \/ _ \/ // / _ `/ _ \/ _ `/
+ * /_/_/_/_/ .__/_/ \__/___/___/_/\___/_//_/\_, /\_,_/_//_/\_, /
+ * /_/ /___/ /___/
+ * @copyright Copyright (c) 2022 impressionyang
+ *
+ * @par 修改日志:
+ *
+ * | Date | Version | Author | Description
+ * |
|---|
| 2022-10-12 | v1.0 | impressionyang | 内容
+ * |
+ */
+#ifndef __LINK_LIST_H__
+#define __LINK_LIST_H__
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/// @brief 链表节点结构
+typedef struct _link_list_node_t_
+{
+ /// @brief 链表节点的位置,如果有删除事件,需要
+ uint8_t node_id;
+ /// @brief 链表数据的指针,所有的链表节点内的数据都是一个指针,方便存放如结构体等数据
+ void *node_data_ptr;
+ /// @brief 下一个元素节点的指针
+ struct _link_list_node_t_ *next;
+}link_list_node_t;
+
+/// @brief 链表控制句柄,用来确认链表的元素和链表头的
+typedef struct _link_list_handle_t_
+{
+ /// @brief 链表节点个数
+ uint8_t link_list_length;
+ /// @brief 链表头
+ link_list_node_t *link_list_header;
+ /// @brief 链表尾
+ link_list_node_t *link_list_tail;
+}link_list_handle_t;
+
+/**
+ *
+ * @brief 初始化链表
+ * 1. 申请内存空间
+ * 2. 返回一个链表句柄
+ * @author impressionyang (impressionyang@outlook.com)
+ * @return link_list_handle_t* 链表控制句柄
+ *
+ * @details
+ */
+link_list_handle_t* link_list_init();
+
+/**
+ *
+ * @brief 将node_data_ptr创建一个链表的节点插入到尾部中
+ * @author impressionyang (impressionyang@outlook.com)
+ * @param [in] link_list 链表控制句柄
+ * @param [in] node_data_ptr 链表节点的数据的指针
+ * @param [out] node_id 返回的该节点在链表中的当前的位置
+ * @return uint8_t 插入结果 0 -》成功 | 非0 -》 失败
+ *
+ * @details
+ */
+uint8_t link_list_append_node_to_tail(link_list_handle_t *link_list, void *node_data_ptr, uint8_t *node_id);
+
+/**
+ *
+ * @brief 通过一个节点指针获取该节点的下一个链表节点的内容
+ * @author impressionyang (impressionyang@outlook.com)
+ * @param [in] link_list 链表控制句柄
+ * @param [in] node 当前节点(一般开始为头节点)
+ * @param [in] node_data_ptr 节点的数据的指针
+ * @return link_list_node_t* 下一个节点的指针
+ *
+ * @details
+ */
+link_list_node_t *link_list_get_next_node(link_list_handle_t *link_list, link_list_node_t *node, void *node_data_ptr);
+
+/**
+ *
+ * @brief 通过位置获取节点的数值
+ * @author impressionyang (impressionyang@outlook.com)
+ * @param [in] link_list 链表控制句柄
+ * @param [in] node_data_ptr 节点数据保存的指针
+ * @param [in] node_id 位置
+ * @return uint8_t 结果 0 -》成功 | 非0 -》 失败
+ *
+ * @details
+ */
+uint8_t link_list_get_node_by_id(link_list_handle_t *link_list, void *node_data_ptr, uint8_t node_id);
+
+/**
+ *
+ * @brief 通过位置删除节点
+ * @author impressionyang (impressionyang@outlook.com)
+ * @param [in] link_list 链表控制句柄
+ * @param [in] node_id 位置
+ * @return uint8_t 结果 0 -》成功 | 非0 -》 失败
+ *
+ * @details
+ */
+uint8_t link_list_delete_node_by_id(link_list_handle_t *link_list, uint8_t node_id);
+
+/**
+ *
+ * @brief 去初始化链表,删除所有元素
+ * @author impressionyang (impressionyang@outlook.com)
+ * @param [in] link_list 链表控制句柄
+ * @return uint8_t 结果 0 -》成功 | 非0 -》 失败
+ *
+ * @details
+ */
+uint8_t link_list_deinit(link_list_handle_t* link_list);
+
+#ifdef __cplusplus
+}
+#endif
+#endif//__LINK_LIST_H__
\ No newline at end of file
diff --git a/sdkconfig b/sdkconfig
new file mode 100644
index 0000000..d676400
--- /dev/null
+++ b/sdkconfig
@@ -0,0 +1,1376 @@
+#
+# Automatically generated file. DO NOT EDIT.
+# Espressif IoT Development Framework (ESP-IDF) Project Configuration
+#
+CONFIG_IDF_CMAKE=y
+CONFIG_IDF_TARGET_ARCH_XTENSA=y
+CONFIG_IDF_TARGET="esp32s2"
+CONFIG_IDF_TARGET_ESP32S2=y
+CONFIG_IDF_FIRMWARE_CHIP_ID=0x0002
+
+#
+# SDK tool configuration
+#
+CONFIG_SDK_TOOLPREFIX="xtensa-esp32s2-elf-"
+# CONFIG_SDK_TOOLCHAIN_SUPPORTS_TIME_WIDE_64_BITS is not set
+# end of SDK tool configuration
+
+#
+# Build type
+#
+CONFIG_APP_BUILD_TYPE_APP_2NDBOOT=y
+# CONFIG_APP_BUILD_TYPE_ELF_RAM is not set
+CONFIG_APP_BUILD_GENERATE_BINARIES=y
+CONFIG_APP_BUILD_BOOTLOADER=y
+CONFIG_APP_BUILD_USE_FLASH_SECTIONS=y
+# end of Build type
+
+#
+# Application manager
+#
+CONFIG_APP_COMPILE_TIME_DATE=y
+# CONFIG_APP_EXCLUDE_PROJECT_VER_VAR is not set
+# CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR is not set
+# CONFIG_APP_PROJECT_VER_FROM_CONFIG is not set
+CONFIG_APP_RETRIEVE_LEN_ELF_SHA=16
+# end of Application manager
+
+#
+# Bootloader config
+#
+CONFIG_BOOTLOADER_OFFSET_IN_FLASH=0x1000
+CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
+# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_DEBUG is not set
+# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_PERF is not set
+# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_NONE is not set
+# CONFIG_BOOTLOADER_LOG_LEVEL_NONE is not set
+# CONFIG_BOOTLOADER_LOG_LEVEL_ERROR is not set
+# CONFIG_BOOTLOADER_LOG_LEVEL_WARN is not set
+CONFIG_BOOTLOADER_LOG_LEVEL_INFO=y
+# CONFIG_BOOTLOADER_LOG_LEVEL_DEBUG is not set
+# CONFIG_BOOTLOADER_LOG_LEVEL_VERBOSE is not set
+CONFIG_BOOTLOADER_LOG_LEVEL=3
+CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_9V=y
+# CONFIG_BOOTLOADER_FACTORY_RESET is not set
+# CONFIG_BOOTLOADER_APP_TEST is not set
+CONFIG_BOOTLOADER_REGION_PROTECTION_ENABLE=y
+CONFIG_BOOTLOADER_WDT_ENABLE=y
+# CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE is not set
+CONFIG_BOOTLOADER_WDT_TIME_MS=9000
+# CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE is not set
+# CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP is not set
+# CONFIG_BOOTLOADER_SKIP_VALIDATE_ON_POWER_ON is not set
+# CONFIG_BOOTLOADER_SKIP_VALIDATE_ALWAYS is not set
+CONFIG_BOOTLOADER_RESERVE_RTC_SIZE=0
+# CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC is not set
+CONFIG_BOOTLOADER_FLASH_XMC_SUPPORT=y
+# end of Bootloader config
+
+#
+# Security features
+#
+CONFIG_SECURE_BOOT_SUPPORTS_RSA=y
+CONFIG_SECURE_TARGET_HAS_SECURE_ROM_DL_MODE=y
+# CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT is not set
+# CONFIG_SECURE_BOOT is not set
+# CONFIG_SECURE_FLASH_ENC_ENABLED is not set
+# end of Security features
+
+#
+# Boot ROM Behavior
+#
+CONFIG_BOOT_ROM_LOG_ALWAYS_ON=y
+# CONFIG_BOOT_ROM_LOG_ALWAYS_OFF is not set
+# CONFIG_BOOT_ROM_LOG_ON_GPIO_HIGH is not set
+# CONFIG_BOOT_ROM_LOG_ON_GPIO_LOW is not set
+# end of Boot ROM Behavior
+
+#
+# Serial flasher config
+#
+CONFIG_ESPTOOLPY_BAUD_OTHER_VAL=115200
+# CONFIG_ESPTOOLPY_NO_STUB is not set
+# CONFIG_ESPTOOLPY_FLASHMODE_QIO is not set
+# CONFIG_ESPTOOLPY_FLASHMODE_QOUT is not set
+CONFIG_ESPTOOLPY_FLASHMODE_DIO=y
+# CONFIG_ESPTOOLPY_FLASHMODE_DOUT is not set
+CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_STR=y
+CONFIG_ESPTOOLPY_FLASHMODE="dio"
+CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
+# CONFIG_ESPTOOLPY_FLASHFREQ_40M is not set
+# CONFIG_ESPTOOLPY_FLASHFREQ_26M is not set
+# CONFIG_ESPTOOLPY_FLASHFREQ_20M is not set
+CONFIG_ESPTOOLPY_FLASHFREQ="80m"
+# CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set
+CONFIG_ESPTOOLPY_FLASHSIZE_2MB=y
+# CONFIG_ESPTOOLPY_FLASHSIZE_4MB is not set
+# CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set
+# CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set
+# CONFIG_ESPTOOLPY_FLASHSIZE_32MB is not set
+# CONFIG_ESPTOOLPY_FLASHSIZE_64MB is not set
+# CONFIG_ESPTOOLPY_FLASHSIZE_128MB is not set
+CONFIG_ESPTOOLPY_FLASHSIZE="2MB"
+CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y
+CONFIG_ESPTOOLPY_BEFORE_RESET=y
+# CONFIG_ESPTOOLPY_BEFORE_NORESET is not set
+CONFIG_ESPTOOLPY_BEFORE="default_reset"
+CONFIG_ESPTOOLPY_AFTER_RESET=y
+# CONFIG_ESPTOOLPY_AFTER_NORESET is not set
+CONFIG_ESPTOOLPY_AFTER="hard_reset"
+# CONFIG_ESPTOOLPY_MONITOR_BAUD_CONSOLE is not set
+# CONFIG_ESPTOOLPY_MONITOR_BAUD_9600B is not set
+# CONFIG_ESPTOOLPY_MONITOR_BAUD_57600B is not set
+CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y
+# CONFIG_ESPTOOLPY_MONITOR_BAUD_230400B is not set
+# CONFIG_ESPTOOLPY_MONITOR_BAUD_921600B is not set
+# CONFIG_ESPTOOLPY_MONITOR_BAUD_2MB is not set
+# CONFIG_ESPTOOLPY_MONITOR_BAUD_OTHER is not set
+CONFIG_ESPTOOLPY_MONITOR_BAUD_OTHER_VAL=115200
+CONFIG_ESPTOOLPY_MONITOR_BAUD=115200
+# end of Serial flasher config
+
+#
+# Partition Table
+#
+CONFIG_PARTITION_TABLE_SINGLE_APP=y
+# CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE is not set
+# CONFIG_PARTITION_TABLE_TWO_OTA is not set
+# CONFIG_PARTITION_TABLE_CUSTOM is not set
+CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
+CONFIG_PARTITION_TABLE_FILENAME="partitions_singleapp.csv"
+CONFIG_PARTITION_TABLE_OFFSET=0x8000
+CONFIG_PARTITION_TABLE_MD5=y
+# end of Partition Table
+
+#
+# ST7789 Configuration
+#
+CONFIG_GPIO_RANGE_MAX=46
+CONFIG_WIDTH=240
+CONFIG_HEIGHT=280
+CONFIG_OFFSETX=0
+CONFIG_OFFSETY=20
+CONFIG_MOSI_GPIO=11
+CONFIG_SCLK_GPIO=12
+CONFIG_CS_GPIO=-1
+CONFIG_DC_GPIO=13
+CONFIG_RESET_GPIO=10
+CONFIG_BL_GPIO=14
+# CONFIG_INVERSION is not set
+# CONFIG_SPI2_HOST is not set
+CONFIG_SPI3_HOST=y
+# end of ST7789 Configuration
+
+#
+# Compiler options
+#
+CONFIG_COMPILER_OPTIMIZATION_DEFAULT=y
+# CONFIG_COMPILER_OPTIMIZATION_SIZE is not set
+# CONFIG_COMPILER_OPTIMIZATION_PERF is not set
+# CONFIG_COMPILER_OPTIMIZATION_NONE is not set
+CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y
+# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT is not set
+# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE is not set
+CONFIG_COMPILER_OPTIMIZATION_ASSERTION_LEVEL=2
+# CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT is not set
+CONFIG_COMPILER_HIDE_PATHS_MACROS=y
+# CONFIG_COMPILER_CXX_EXCEPTIONS is not set
+# CONFIG_COMPILER_CXX_RTTI is not set
+CONFIG_COMPILER_STACK_CHECK_MODE_NONE=y
+# CONFIG_COMPILER_STACK_CHECK_MODE_NORM is not set
+# CONFIG_COMPILER_STACK_CHECK_MODE_STRONG is not set
+# CONFIG_COMPILER_STACK_CHECK_MODE_ALL is not set
+# CONFIG_COMPILER_WARN_WRITE_STRINGS is not set
+# CONFIG_COMPILER_DISABLE_GCC8_WARNINGS is not set
+# CONFIG_COMPILER_DUMP_RTL_FILES is not set
+# end of Compiler options
+
+#
+# Component config
+#
+
+#
+# Application Level Tracing
+#
+# CONFIG_APPTRACE_DEST_JTAG is not set
+CONFIG_APPTRACE_DEST_NONE=y
+CONFIG_APPTRACE_LOCK_ENABLE=y
+# end of Application Level Tracing
+
+#
+# ESP-ASIO
+#
+# CONFIG_ASIO_SSL_SUPPORT is not set
+# end of ESP-ASIO
+
+#
+# CoAP Configuration
+#
+CONFIG_COAP_MBEDTLS_PSK=y
+# CONFIG_COAP_MBEDTLS_PKI is not set
+# CONFIG_COAP_MBEDTLS_DEBUG is not set
+CONFIG_COAP_LOG_DEFAULT_LEVEL=0
+# end of CoAP Configuration
+
+#
+# Driver configurations
+#
+
+#
+# ADC configuration
+#
+# CONFIG_ADC_FORCE_XPD_FSM is not set
+CONFIG_ADC_DISABLE_DAC=y
+# end of ADC configuration
+
+#
+# MCPWM configuration
+#
+# CONFIG_MCPWM_ISR_IN_IRAM is not set
+# end of MCPWM configuration
+
+#
+# SPI configuration
+#
+# CONFIG_SPI_MASTER_IN_IRAM is not set
+CONFIG_SPI_MASTER_ISR_IN_IRAM=y
+# CONFIG_SPI_SLAVE_IN_IRAM is not set
+CONFIG_SPI_SLAVE_ISR_IN_IRAM=y
+# end of SPI configuration
+
+#
+# TWAI configuration
+#
+# CONFIG_TWAI_ISR_IN_IRAM is not set
+# end of TWAI configuration
+
+#
+# UART configuration
+#
+# CONFIG_UART_ISR_IN_IRAM is not set
+# end of UART configuration
+
+#
+# GDMA Configuration
+#
+# CONFIG_GDMA_CTRL_FUNC_IN_IRAM is not set
+# CONFIG_GDMA_ISR_IRAM_SAFE is not set
+# end of GDMA Configuration
+# end of Driver configurations
+
+#
+# eFuse Bit Manager
+#
+# CONFIG_EFUSE_CUSTOM_TABLE is not set
+# CONFIG_EFUSE_VIRTUAL is not set
+CONFIG_EFUSE_MAX_BLK_LEN=256
+# end of eFuse Bit Manager
+
+#
+# ESP-TLS
+#
+CONFIG_ESP_TLS_USING_MBEDTLS=y
+CONFIG_ESP_TLS_USE_DS_PERIPHERAL=y
+# CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS is not set
+# CONFIG_ESP_TLS_SERVER is not set
+# CONFIG_ESP_TLS_PSK_VERIFICATION is not set
+# CONFIG_ESP_TLS_INSECURE is not set
+# end of ESP-TLS
+
+#
+# ESP32S2-specific
+#
+# CONFIG_ESP32S2_DEFAULT_CPU_FREQ_80 is not set
+CONFIG_ESP32S2_DEFAULT_CPU_FREQ_160=y
+# CONFIG_ESP32S2_DEFAULT_CPU_FREQ_240 is not set
+CONFIG_ESP32S2_DEFAULT_CPU_FREQ_MHZ=160
+
+#
+# Cache config
+#
+CONFIG_ESP32S2_INSTRUCTION_CACHE_8KB=y
+# CONFIG_ESP32S2_INSTRUCTION_CACHE_16KB is not set
+# CONFIG_ESP32S2_INSTRUCTION_CACHE_LINE_16B is not set
+CONFIG_ESP32S2_INSTRUCTION_CACHE_LINE_32B=y
+CONFIG_ESP32S2_DATA_CACHE_0KB=y
+# CONFIG_ESP32S2_DATA_CACHE_8KB is not set
+# CONFIG_ESP32S2_DATA_CACHE_16KB is not set
+# CONFIG_ESP32S2_DATA_CACHE_LINE_16B is not set
+CONFIG_ESP32S2_DATA_CACHE_LINE_32B=y
+# CONFIG_ESP32S2_INSTRUCTION_CACHE_WRAP is not set
+# CONFIG_ESP32S2_DATA_CACHE_WRAP is not set
+# end of Cache config
+
+# CONFIG_ESP32S2_SPIRAM_SUPPORT is not set
+# CONFIG_ESP32S2_TRAX is not set
+CONFIG_ESP32S2_TRACEMEM_RESERVE_DRAM=0x0
+# CONFIG_ESP32S2_ULP_COPROC_ENABLED is not set
+CONFIG_ESP32S2_ULP_COPROC_RESERVE_MEM=0
+CONFIG_ESP32S2_DEBUG_OCDAWARE=y
+CONFIG_ESP32S2_BROWNOUT_DET=y
+CONFIG_ESP32S2_BROWNOUT_DET_LVL_SEL_7=y
+# CONFIG_ESP32S2_BROWNOUT_DET_LVL_SEL_6 is not set
+# CONFIG_ESP32S2_BROWNOUT_DET_LVL_SEL_5 is not set
+# CONFIG_ESP32S2_BROWNOUT_DET_LVL_SEL_4 is not set
+# CONFIG_ESP32S2_BROWNOUT_DET_LVL_SEL_3 is not set
+# CONFIG_ESP32S2_BROWNOUT_DET_LVL_SEL_2 is not set
+# CONFIG_ESP32S2_BROWNOUT_DET_LVL_SEL_1 is not set
+CONFIG_ESP32S2_BROWNOUT_DET_LVL=7
+CONFIG_ESP32S2_TIME_SYSCALL_USE_RTC_FRC1=y
+# CONFIG_ESP32S2_TIME_SYSCALL_USE_RTC is not set
+# CONFIG_ESP32S2_TIME_SYSCALL_USE_FRC1 is not set
+# CONFIG_ESP32S2_TIME_SYSCALL_USE_NONE is not set
+CONFIG_ESP32S2_RTC_CLK_SRC_INT_RC=y
+# CONFIG_ESP32S2_RTC_CLK_SRC_EXT_CRYS is not set
+# CONFIG_ESP32S2_RTC_CLK_SRC_EXT_OSC is not set
+# CONFIG_ESP32S2_RTC_CLK_SRC_INT_8MD256 is not set
+CONFIG_ESP32S2_RTC_CLK_CAL_CYCLES=576
+# CONFIG_ESP32S2_NO_BLOBS is not set
+# CONFIG_ESP32S2_KEEP_USB_ALIVE is not set
+# CONFIG_ESP32S2_RTCDATA_IN_FAST_MEM is not set
+# CONFIG_ESP32S2_USE_FIXED_STATIC_RAM_SIZE is not set
+# end of ESP32S2-specific
+
+#
+# ADC-Calibration
+#
+# end of ADC-Calibration
+
+#
+# Common ESP-related
+#
+CONFIG_ESP_ERR_TO_NAME_LOOKUP=y
+# end of Common ESP-related
+
+#
+# Ethernet
+#
+CONFIG_ETH_ENABLED=y
+CONFIG_ETH_USE_SPI_ETHERNET=y
+# CONFIG_ETH_SPI_ETHERNET_DM9051 is not set
+# CONFIG_ETH_SPI_ETHERNET_W5500 is not set
+# CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL is not set
+# CONFIG_ETH_USE_OPENETH is not set
+# end of Ethernet
+
+#
+# Event Loop Library
+#
+# CONFIG_ESP_EVENT_LOOP_PROFILING is not set
+CONFIG_ESP_EVENT_POST_FROM_ISR=y
+CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR=y
+# end of Event Loop Library
+
+#
+# GDB Stub
+#
+# end of GDB Stub
+
+#
+# ESP HTTP client
+#
+CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y
+# CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH is not set
+CONFIG_ESP_HTTP_CLIENT_ENABLE_DIGEST_AUTH=y
+# end of ESP HTTP client
+
+#
+# HTTP Server
+#
+CONFIG_HTTPD_MAX_REQ_HDR_LEN=512
+CONFIG_HTTPD_MAX_URI_LEN=512
+CONFIG_HTTPD_ERR_RESP_NO_DELAY=y
+CONFIG_HTTPD_PURGE_BUF_LEN=32
+# CONFIG_HTTPD_LOG_PURGE_DATA is not set
+# CONFIG_HTTPD_WS_SUPPORT is not set
+# end of HTTP Server
+
+#
+# ESP HTTPS OTA
+#
+# CONFIG_OTA_ALLOW_HTTP is not set
+# end of ESP HTTPS OTA
+
+#
+# ESP HTTPS server
+#
+# CONFIG_ESP_HTTPS_SERVER_ENABLE is not set
+# end of ESP HTTPS server
+
+#
+# Hardware Settings
+#
+
+#
+# MAC Config
+#
+CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_STA=y
+CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_AP=y
+# CONFIG_ESP32S2_UNIVERSAL_MAC_ADDRESSES_ONE is not set
+CONFIG_ESP32S2_UNIVERSAL_MAC_ADDRESSES_TWO=y
+CONFIG_ESP32S2_UNIVERSAL_MAC_ADDRESSES=2
+# end of MAC Config
+
+#
+# Sleep Config
+#
+CONFIG_ESP_SLEEP_POWER_DOWN_FLASH=y
+CONFIG_ESP_SLEEP_RTC_BUS_ISO_WORKAROUND=y
+# CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND is not set
+# CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND is not set
+# end of Sleep Config
+
+#
+# RTC Clock Config
+#
+# end of RTC Clock Config
+# end of Hardware Settings
+
+#
+# IPC (Inter-Processor Call)
+#
+CONFIG_ESP_IPC_TASK_STACK_SIZE=1536
+# end of IPC (Inter-Processor Call)
+
+#
+# LCD and Touch Panel
+#
+
+#
+# LCD Peripheral Configuration
+#
+CONFIG_LCD_PANEL_IO_FORMAT_BUF_SIZE=32
+# end of LCD Peripheral Configuration
+# end of LCD and Touch Panel
+
+#
+# ESP NETIF Adapter
+#
+CONFIG_ESP_NETIF_IP_LOST_TIMER_INTERVAL=120
+CONFIG_ESP_NETIF_TCPIP_LWIP=y
+# CONFIG_ESP_NETIF_LOOPBACK is not set
+CONFIG_ESP_NETIF_TCPIP_ADAPTER_COMPATIBLE_LAYER=y
+# end of ESP NETIF Adapter
+
+#
+# PHY
+#
+CONFIG_ESP_PHY_CALIBRATION_AND_DATA_STORAGE=y
+# CONFIG_ESP_PHY_INIT_DATA_IN_PARTITION is not set
+CONFIG_ESP_PHY_MAX_WIFI_TX_POWER=20
+CONFIG_ESP_PHY_MAX_TX_POWER=20
+# CONFIG_ESP_PHY_ENABLE_USB is not set
+# end of PHY
+
+#
+# Power Management
+#
+# CONFIG_PM_ENABLE is not set
+# end of Power Management
+
+#
+# ESP System Settings
+#
+# CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT is not set
+CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT=y
+# CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT is not set
+# CONFIG_ESP_SYSTEM_PANIC_GDBSTUB is not set
+# CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME is not set
+CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE=y
+CONFIG_ESP_SYSTEM_RTC_FAST_MEM_AS_HEAP_DEPCHECK=y
+CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP=y
+
+#
+# Memory protection
+#
+CONFIG_ESP_SYSTEM_MEMPROT_DEPCHECK=y
+CONFIG_ESP_SYSTEM_MEMPROT_FEATURE=y
+CONFIG_ESP_SYSTEM_MEMPROT_FEATURE_LOCK=y
+CONFIG_ESP_SYSTEM_MEMPROT_CPU_PREFETCH_PAD_SIZE=16
+CONFIG_ESP_SYSTEM_MEMPROT_MEM_ALIGN_SIZE=4
+# end of Memory protection
+
+CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE=32
+CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=2304
+CONFIG_ESP_MAIN_TASK_STACK_SIZE=3584
+CONFIG_ESP_MAIN_TASK_AFFINITY_CPU0=y
+# CONFIG_ESP_MAIN_TASK_AFFINITY_NO_AFFINITY is not set
+CONFIG_ESP_MAIN_TASK_AFFINITY=0x0
+CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE=2048
+CONFIG_ESP_CONSOLE_UART_DEFAULT=y
+# CONFIG_ESP_CONSOLE_USB_CDC is not set
+# CONFIG_ESP_CONSOLE_UART_CUSTOM is not set
+# CONFIG_ESP_CONSOLE_NONE is not set
+CONFIG_ESP_CONSOLE_UART=y
+CONFIG_ESP_CONSOLE_MULTIPLE_UART=y
+CONFIG_ESP_CONSOLE_UART_NUM=0
+CONFIG_ESP_CONSOLE_UART_BAUDRATE=115200
+CONFIG_ESP_INT_WDT=y
+CONFIG_ESP_INT_WDT_TIMEOUT_MS=300
+CONFIG_ESP_TASK_WDT=y
+# CONFIG_ESP_TASK_WDT_PANIC is not set
+CONFIG_ESP_TASK_WDT_TIMEOUT_S=5
+CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0=y
+# CONFIG_ESP_PANIC_HANDLER_IRAM is not set
+# CONFIG_ESP_DEBUG_STUBS_ENABLE is not set
+CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_4=y
+# end of ESP System Settings
+
+#
+# High resolution timer (esp_timer)
+#
+# CONFIG_ESP_TIMER_PROFILING is not set
+CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER=y
+CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER=y
+CONFIG_ESP_TIMER_TASK_STACK_SIZE=3584
+CONFIG_ESP_TIMER_INTERRUPT_LEVEL=1
+# CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD is not set
+CONFIG_ESP_TIMER_IMPL_SYSTIMER=y
+# end of High resolution timer (esp_timer)
+
+#
+# Wi-Fi
+#
+CONFIG_ESP32_WIFI_ENABLED=y
+CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=10
+CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=32
+# CONFIG_ESP32_WIFI_STATIC_TX_BUFFER is not set
+CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER=y
+CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=1
+CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM=32
+# CONFIG_ESP32_WIFI_CSI_ENABLED is not set
+CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED=y
+CONFIG_ESP32_WIFI_TX_BA_WIN=6
+CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED=y
+CONFIG_ESP32_WIFI_RX_BA_WIN=6
+CONFIG_ESP32_WIFI_NVS_ENABLED=y
+CONFIG_ESP32_WIFI_SOFTAP_BEACON_MAX_LEN=752
+CONFIG_ESP32_WIFI_MGMT_SBUF_NUM=32
+CONFIG_ESP32_WIFI_IRAM_OPT=y
+CONFIG_ESP32_WIFI_RX_IRAM_OPT=y
+CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE=y
+# CONFIG_ESP_WIFI_SLP_IRAM_OPT is not set
+# CONFIG_ESP_WIFI_FTM_ENABLE is not set
+# CONFIG_ESP_WIFI_STA_DISCONNECTED_PM_ENABLE is not set
+# CONFIG_ESP_WIFI_EXTERNAL_COEXIST_ENABLE is not set
+# CONFIG_ESP_WIFI_GMAC_SUPPORT is not set
+CONFIG_ESP_WIFI_SOFTAP_SUPPORT=y
+# end of Wi-Fi
+
+#
+# Core dump
+#
+# CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH is not set
+# CONFIG_ESP_COREDUMP_ENABLE_TO_UART is not set
+CONFIG_ESP_COREDUMP_ENABLE_TO_NONE=y
+# end of Core dump
+
+#
+# FAT Filesystem support
+#
+# CONFIG_FATFS_CODEPAGE_DYNAMIC is not set
+CONFIG_FATFS_CODEPAGE_437=y
+# CONFIG_FATFS_CODEPAGE_720 is not set
+# CONFIG_FATFS_CODEPAGE_737 is not set
+# CONFIG_FATFS_CODEPAGE_771 is not set
+# CONFIG_FATFS_CODEPAGE_775 is not set
+# CONFIG_FATFS_CODEPAGE_850 is not set
+# CONFIG_FATFS_CODEPAGE_852 is not set
+# CONFIG_FATFS_CODEPAGE_855 is not set
+# CONFIG_FATFS_CODEPAGE_857 is not set
+# CONFIG_FATFS_CODEPAGE_860 is not set
+# CONFIG_FATFS_CODEPAGE_861 is not set
+# CONFIG_FATFS_CODEPAGE_862 is not set
+# CONFIG_FATFS_CODEPAGE_863 is not set
+# CONFIG_FATFS_CODEPAGE_864 is not set
+# CONFIG_FATFS_CODEPAGE_865 is not set
+# CONFIG_FATFS_CODEPAGE_866 is not set
+# CONFIG_FATFS_CODEPAGE_869 is not set
+# CONFIG_FATFS_CODEPAGE_932 is not set
+# CONFIG_FATFS_CODEPAGE_936 is not set
+# CONFIG_FATFS_CODEPAGE_949 is not set
+# CONFIG_FATFS_CODEPAGE_950 is not set
+CONFIG_FATFS_CODEPAGE=437
+CONFIG_FATFS_LFN_NONE=y
+# CONFIG_FATFS_LFN_HEAP is not set
+# CONFIG_FATFS_LFN_STACK is not set
+CONFIG_FATFS_FS_LOCK=0
+CONFIG_FATFS_TIMEOUT_MS=10000
+CONFIG_FATFS_PER_FILE_CACHE=y
+# CONFIG_FATFS_USE_FASTSEEK is not set
+# end of FAT Filesystem support
+
+#
+# Modbus configuration
+#
+CONFIG_FMB_COMM_MODE_TCP_EN=y
+CONFIG_FMB_TCP_PORT_DEFAULT=502
+CONFIG_FMB_TCP_PORT_MAX_CONN=5
+CONFIG_FMB_TCP_CONNECTION_TOUT_SEC=20
+CONFIG_FMB_COMM_MODE_RTU_EN=y
+CONFIG_FMB_COMM_MODE_ASCII_EN=y
+CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND=150
+CONFIG_FMB_MASTER_DELAY_MS_CONVERT=200
+CONFIG_FMB_QUEUE_LENGTH=20
+CONFIG_FMB_PORT_TASK_STACK_SIZE=4096
+CONFIG_FMB_SERIAL_BUF_SIZE=256
+CONFIG_FMB_SERIAL_ASCII_BITS_PER_SYMB=8
+CONFIG_FMB_SERIAL_ASCII_TIMEOUT_RESPOND_MS=1000
+CONFIG_FMB_PORT_TASK_PRIO=10
+CONFIG_FMB_PORT_TASK_AFFINITY=0x7FFFFFFF
+CONFIG_FMB_CONTROLLER_SLAVE_ID_SUPPORT=y
+CONFIG_FMB_CONTROLLER_SLAVE_ID=0x00112233
+CONFIG_FMB_CONTROLLER_NOTIFY_TIMEOUT=20
+CONFIG_FMB_CONTROLLER_NOTIFY_QUEUE_SIZE=20
+CONFIG_FMB_CONTROLLER_STACK_SIZE=4096
+CONFIG_FMB_EVENT_QUEUE_TIMEOUT=20
+# CONFIG_FMB_TIMER_PORT_ENABLED is not set
+CONFIG_FMB_TIMER_GROUP=0
+CONFIG_FMB_TIMER_INDEX=0
+CONFIG_FMB_MASTER_TIMER_GROUP=0
+CONFIG_FMB_MASTER_TIMER_INDEX=0
+# CONFIG_FMB_TIMER_ISR_IN_IRAM is not set
+# end of Modbus configuration
+
+#
+# FreeRTOS
+#
+CONFIG_FREERTOS_UNICORE=y
+CONFIG_FREERTOS_NO_AFFINITY=0x7FFFFFFF
+CONFIG_FREERTOS_TICK_SUPPORT_CORETIMER=y
+CONFIG_FREERTOS_CORETIMER_0=y
+# CONFIG_FREERTOS_CORETIMER_1 is not set
+CONFIG_FREERTOS_SYSTICK_USES_CCOUNT=y
+CONFIG_FREERTOS_OPTIMIZED_SCHEDULER=y
+CONFIG_FREERTOS_HZ=100
+CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION=y
+# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE is not set
+# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_PTRVAL is not set
+CONFIG_FREERTOS_CHECK_STACKOVERFLOW_CANARY=y
+# CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK is not set
+CONFIG_FREERTOS_INTERRUPT_BACKTRACE=y
+CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=1
+CONFIG_FREERTOS_ASSERT_FAIL_ABORT=y
+# CONFIG_FREERTOS_ASSERT_FAIL_PRINT_CONTINUE is not set
+# CONFIG_FREERTOS_ASSERT_DISABLE is not set
+CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1536
+CONFIG_FREERTOS_ISR_STACKSIZE=1536
+# CONFIG_FREERTOS_LEGACY_HOOKS is not set
+CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16
+CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y
+# CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP is not set
+CONFIG_FREERTOS_TIMER_TASK_PRIORITY=1
+CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=2048
+CONFIG_FREERTOS_TIMER_QUEUE_LENGTH=10
+CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=0
+CONFIG_FREERTOS_USE_TRACE_FACILITY=y
+CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS=y
+# CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID is not set
+CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=y
+CONFIG_FREERTOS_RUN_TIME_STATS_USING_ESP_TIMER=y
+# CONFIG_FREERTOS_RUN_TIME_STATS_USING_CPU_CLK is not set
+CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER=y
+CONFIG_FREERTOS_CHECK_MUTEX_GIVEN_BY_OWNER=y
+# CONFIG_FREERTOS_CHECK_PORT_CRITICAL_COMPLIANCE is not set
+# CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH is not set
+CONFIG_FREERTOS_DEBUG_OCDAWARE=y
+CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT=y
+# CONFIG_FREERTOS_PLACE_SNAPSHOT_FUNS_INTO_FLASH is not set
+# end of FreeRTOS
+
+#
+# Hardware Abstraction Layer (HAL) and Low Level (LL)
+#
+CONFIG_HAL_ASSERTION_EQUALS_SYSTEM=y
+# CONFIG_HAL_ASSERTION_DISABLE is not set
+# CONFIG_HAL_ASSERTION_SILIENT is not set
+# CONFIG_HAL_ASSERTION_ENABLE is not set
+CONFIG_HAL_DEFAULT_ASSERTION_LEVEL=2
+# end of Hardware Abstraction Layer (HAL) and Low Level (LL)
+
+#
+# Heap memory debugging
+#
+CONFIG_HEAP_POISONING_DISABLED=y
+# CONFIG_HEAP_POISONING_LIGHT is not set
+# CONFIG_HEAP_POISONING_COMPREHENSIVE is not set
+CONFIG_HEAP_TRACING_OFF=y
+# CONFIG_HEAP_TRACING_STANDALONE is not set
+# CONFIG_HEAP_TRACING_TOHOST is not set
+# CONFIG_HEAP_ABORT_WHEN_ALLOCATION_FAILS is not set
+# end of Heap memory debugging
+
+#
+# jsmn
+#
+# CONFIG_JSMN_PARENT_LINKS is not set
+# CONFIG_JSMN_STRICT is not set
+# end of jsmn
+
+#
+# libsodium
+#
+# end of libsodium
+
+#
+# Log output
+#
+# CONFIG_LOG_DEFAULT_LEVEL_NONE is not set
+# CONFIG_LOG_DEFAULT_LEVEL_ERROR is not set
+# CONFIG_LOG_DEFAULT_LEVEL_WARN is not set
+CONFIG_LOG_DEFAULT_LEVEL_INFO=y
+# CONFIG_LOG_DEFAULT_LEVEL_DEBUG is not set
+# CONFIG_LOG_DEFAULT_LEVEL_VERBOSE is not set
+CONFIG_LOG_DEFAULT_LEVEL=3
+CONFIG_LOG_MAXIMUM_EQUALS_DEFAULT=y
+# CONFIG_LOG_MAXIMUM_LEVEL_DEBUG is not set
+# CONFIG_LOG_MAXIMUM_LEVEL_VERBOSE is not set
+CONFIG_LOG_MAXIMUM_LEVEL=3
+CONFIG_LOG_COLORS=y
+CONFIG_LOG_TIMESTAMP_SOURCE_RTOS=y
+# CONFIG_LOG_TIMESTAMP_SOURCE_SYSTEM is not set
+# end of Log output
+
+#
+# LWIP
+#
+CONFIG_LWIP_LOCAL_HOSTNAME="espressif"
+# CONFIG_LWIP_NETIF_API is not set
+# CONFIG_LWIP_TCPIP_CORE_LOCKING is not set
+CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=y
+# CONFIG_LWIP_L2_TO_L3_COPY is not set
+# CONFIG_LWIP_IRAM_OPTIMIZATION is not set
+CONFIG_LWIP_TIMERS_ONDEMAND=y
+CONFIG_LWIP_MAX_SOCKETS=10
+# CONFIG_LWIP_USE_ONLY_LWIP_SELECT is not set
+# CONFIG_LWIP_SO_LINGER is not set
+CONFIG_LWIP_SO_REUSE=y
+CONFIG_LWIP_SO_REUSE_RXTOALL=y
+# CONFIG_LWIP_SO_RCVBUF is not set
+# CONFIG_LWIP_NETBUF_RECVINFO is not set
+CONFIG_LWIP_IP4_FRAG=y
+CONFIG_LWIP_IP6_FRAG=y
+# CONFIG_LWIP_IP4_REASSEMBLY is not set
+# CONFIG_LWIP_IP6_REASSEMBLY is not set
+# CONFIG_LWIP_IP_FORWARD is not set
+# CONFIG_LWIP_STATS is not set
+# CONFIG_LWIP_ETHARP_TRUST_IP_MAC is not set
+CONFIG_LWIP_ESP_GRATUITOUS_ARP=y
+CONFIG_LWIP_GARP_TMR_INTERVAL=60
+CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=32
+CONFIG_LWIP_DHCP_DOES_ARP_CHECK=y
+# CONFIG_LWIP_DHCP_DISABLE_CLIENT_ID is not set
+CONFIG_LWIP_DHCP_DISABLE_VENDOR_CLASS_ID=y
+# CONFIG_LWIP_DHCP_RESTORE_LAST_IP is not set
+CONFIG_LWIP_DHCP_OPTIONS_LEN=68
+
+#
+# DHCP server
+#
+CONFIG_LWIP_DHCPS=y
+CONFIG_LWIP_DHCPS_LEASE_UNIT=60
+CONFIG_LWIP_DHCPS_MAX_STATION_NUM=8
+# end of DHCP server
+
+# CONFIG_LWIP_AUTOIP is not set
+CONFIG_LWIP_IPV6=y
+# CONFIG_LWIP_IPV6_AUTOCONFIG is not set
+CONFIG_LWIP_IPV6_NUM_ADDRESSES=3
+# CONFIG_LWIP_IPV6_FORWARD is not set
+# CONFIG_LWIP_NETIF_STATUS_CALLBACK is not set
+CONFIG_LWIP_NETIF_LOOPBACK=y
+CONFIG_LWIP_LOOPBACK_MAX_PBUFS=8
+
+#
+# TCP
+#
+CONFIG_LWIP_MAX_ACTIVE_TCP=16
+CONFIG_LWIP_MAX_LISTENING_TCP=16
+CONFIG_LWIP_TCP_HIGH_SPEED_RETRANSMISSION=y
+CONFIG_LWIP_TCP_MAXRTX=12
+CONFIG_LWIP_TCP_SYNMAXRTX=12
+CONFIG_LWIP_TCP_MSS=1440
+CONFIG_LWIP_TCP_TMR_INTERVAL=250
+CONFIG_LWIP_TCP_MSL=60000
+CONFIG_LWIP_TCP_SND_BUF_DEFAULT=5744
+CONFIG_LWIP_TCP_WND_DEFAULT=5744
+CONFIG_LWIP_TCP_RECVMBOX_SIZE=6
+CONFIG_LWIP_TCP_QUEUE_OOSEQ=y
+# CONFIG_LWIP_TCP_SACK_OUT is not set
+# CONFIG_LWIP_TCP_KEEP_CONNECTION_WHEN_IP_CHANGES is not set
+CONFIG_LWIP_TCP_OVERSIZE_MSS=y
+# CONFIG_LWIP_TCP_OVERSIZE_QUARTER_MSS is not set
+# CONFIG_LWIP_TCP_OVERSIZE_DISABLE is not set
+CONFIG_LWIP_TCP_RTO_TIME=1500
+# end of TCP
+
+#
+# UDP
+#
+CONFIG_LWIP_MAX_UDP_PCBS=16
+CONFIG_LWIP_UDP_RECVMBOX_SIZE=6
+# end of UDP
+
+#
+# Checksums
+#
+# CONFIG_LWIP_CHECKSUM_CHECK_IP is not set
+# CONFIG_LWIP_CHECKSUM_CHECK_UDP is not set
+CONFIG_LWIP_CHECKSUM_CHECK_ICMP=y
+# end of Checksums
+
+CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=3072
+CONFIG_LWIP_TCPIP_TASK_AFFINITY_NO_AFFINITY=y
+# CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU0 is not set
+CONFIG_LWIP_TCPIP_TASK_AFFINITY=0x7FFFFFFF
+# CONFIG_LWIP_PPP_SUPPORT is not set
+CONFIG_LWIP_IPV6_MEMP_NUM_ND6_QUEUE=3
+CONFIG_LWIP_IPV6_ND6_NUM_NEIGHBORS=5
+# CONFIG_LWIP_SLIP_SUPPORT is not set
+
+#
+# ICMP
+#
+CONFIG_LWIP_ICMP=y
+# CONFIG_LWIP_MULTICAST_PING is not set
+# CONFIG_LWIP_BROADCAST_PING is not set
+# end of ICMP
+
+#
+# LWIP RAW API
+#
+CONFIG_LWIP_MAX_RAW_PCBS=16
+# end of LWIP RAW API
+
+#
+# SNTP
+#
+CONFIG_LWIP_SNTP_MAX_SERVERS=1
+# CONFIG_LWIP_DHCP_GET_NTP_SRV is not set
+CONFIG_LWIP_SNTP_UPDATE_DELAY=3600000
+# end of SNTP
+
+CONFIG_LWIP_ESP_LWIP_ASSERT=y
+
+#
+# Hooks
+#
+# CONFIG_LWIP_HOOK_TCP_ISN_NONE is not set
+CONFIG_LWIP_HOOK_TCP_ISN_DEFAULT=y
+# CONFIG_LWIP_HOOK_TCP_ISN_CUSTOM is not set
+CONFIG_LWIP_HOOK_IP6_ROUTE_NONE=y
+# CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT is not set
+# CONFIG_LWIP_HOOK_IP6_ROUTE_CUSTOM is not set
+CONFIG_LWIP_HOOK_ND6_GET_GW_NONE=y
+# CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT is not set
+# CONFIG_LWIP_HOOK_ND6_GET_GW_CUSTOM is not set
+CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_NONE=y
+# CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_DEFAULT is not set
+# CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_CUSTOM is not set
+# end of Hooks
+
+# CONFIG_LWIP_DEBUG is not set
+# end of LWIP
+
+#
+# mbedTLS
+#
+CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
+# CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC is not set
+# CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC is not set
+CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y
+CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN=16384
+CONFIG_MBEDTLS_SSL_OUT_CONTENT_LEN=4096
+# CONFIG_MBEDTLS_DYNAMIC_BUFFER is not set
+# CONFIG_MBEDTLS_DEBUG is not set
+
+#
+# mbedTLS v2.28.x related
+#
+# CONFIG_MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH is not set
+# CONFIG_MBEDTLS_X509_TRUSTED_CERT_CALLBACK is not set
+# CONFIG_MBEDTLS_SSL_CONTEXT_SERIALIZATION is not set
+CONFIG_MBEDTLS_SSL_KEEP_PEER_CERTIFICATE=y
+# end of mbedTLS v2.28.x related
+
+#
+# Certificate Bundle
+#
+CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=y
+CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL=y
+# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN is not set
+# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_NONE is not set
+# CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE is not set
+CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_MAX_CERTS=200
+# end of Certificate Bundle
+
+# CONFIG_MBEDTLS_ECP_RESTARTABLE is not set
+# CONFIG_MBEDTLS_CMAC_C is not set
+CONFIG_MBEDTLS_HARDWARE_AES=y
+CONFIG_MBEDTLS_AES_USE_INTERRUPT=y
+CONFIG_MBEDTLS_HARDWARE_GCM=y
+CONFIG_MBEDTLS_HARDWARE_MPI=y
+CONFIG_MBEDTLS_HARDWARE_SHA=y
+CONFIG_MBEDTLS_ROM_MD5=y
+# CONFIG_MBEDTLS_ATCA_HW_ECDSA_SIGN is not set
+# CONFIG_MBEDTLS_ATCA_HW_ECDSA_VERIFY is not set
+CONFIG_MBEDTLS_HAVE_TIME=y
+# CONFIG_MBEDTLS_HAVE_TIME_DATE is not set
+CONFIG_MBEDTLS_ECDSA_DETERMINISTIC=y
+CONFIG_MBEDTLS_SHA512_C=y
+CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT=y
+# CONFIG_MBEDTLS_TLS_SERVER_ONLY is not set
+# CONFIG_MBEDTLS_TLS_CLIENT_ONLY is not set
+# CONFIG_MBEDTLS_TLS_DISABLED is not set
+CONFIG_MBEDTLS_TLS_SERVER=y
+CONFIG_MBEDTLS_TLS_CLIENT=y
+CONFIG_MBEDTLS_TLS_ENABLED=y
+
+#
+# TLS Key Exchange Methods
+#
+# CONFIG_MBEDTLS_PSK_MODES is not set
+CONFIG_MBEDTLS_KEY_EXCHANGE_RSA=y
+CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA=y
+CONFIG_MBEDTLS_KEY_EXCHANGE_ELLIPTIC_CURVE=y
+CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA=y
+CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA=y
+CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA=y
+CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_RSA=y
+# end of TLS Key Exchange Methods
+
+CONFIG_MBEDTLS_SSL_RENEGOTIATION=y
+# CONFIG_MBEDTLS_SSL_PROTO_SSL3 is not set
+CONFIG_MBEDTLS_SSL_PROTO_TLS1=y
+CONFIG_MBEDTLS_SSL_PROTO_TLS1_1=y
+CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y
+# CONFIG_MBEDTLS_SSL_PROTO_GMTSSL1_1 is not set
+# CONFIG_MBEDTLS_SSL_PROTO_DTLS is not set
+CONFIG_MBEDTLS_SSL_ALPN=y
+CONFIG_MBEDTLS_CLIENT_SSL_SESSION_TICKETS=y
+CONFIG_MBEDTLS_X509_CHECK_KEY_USAGE=y
+CONFIG_MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE=y
+CONFIG_MBEDTLS_SERVER_SSL_SESSION_TICKETS=y
+
+#
+# Symmetric Ciphers
+#
+CONFIG_MBEDTLS_AES_C=y
+# CONFIG_MBEDTLS_CAMELLIA_C is not set
+# CONFIG_MBEDTLS_DES_C is not set
+CONFIG_MBEDTLS_RC4_DISABLED=y
+# CONFIG_MBEDTLS_RC4_ENABLED_NO_DEFAULT is not set
+# CONFIG_MBEDTLS_RC4_ENABLED is not set
+# CONFIG_MBEDTLS_BLOWFISH_C is not set
+# CONFIG_MBEDTLS_XTEA_C is not set
+CONFIG_MBEDTLS_CCM_C=y
+CONFIG_MBEDTLS_GCM_C=y
+# CONFIG_MBEDTLS_NIST_KW_C is not set
+# end of Symmetric Ciphers
+
+# CONFIG_MBEDTLS_RIPEMD160_C is not set
+
+#
+# Certificates
+#
+CONFIG_MBEDTLS_PEM_PARSE_C=y
+CONFIG_MBEDTLS_PEM_WRITE_C=y
+CONFIG_MBEDTLS_X509_CRL_PARSE_C=y
+CONFIG_MBEDTLS_X509_CSR_PARSE_C=y
+# end of Certificates
+
+CONFIG_MBEDTLS_ECP_C=y
+CONFIG_MBEDTLS_ECDH_C=y
+CONFIG_MBEDTLS_ECDSA_C=y
+# CONFIG_MBEDTLS_ECJPAKE_C is not set
+CONFIG_MBEDTLS_ECP_DP_SECP192R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP224R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP384R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP521R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP192K1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP224K1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP256K1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_BP256R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_BP384R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_BP512R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_CURVE25519_ENABLED=y
+CONFIG_MBEDTLS_ECP_NIST_OPTIM=y
+# CONFIG_MBEDTLS_POLY1305_C is not set
+# CONFIG_MBEDTLS_CHACHA20_C is not set
+# CONFIG_MBEDTLS_HKDF_C is not set
+# CONFIG_MBEDTLS_THREADING_C is not set
+# CONFIG_MBEDTLS_LARGE_KEY_SOFTWARE_MPI is not set
+# CONFIG_MBEDTLS_SECURITY_RISKS is not set
+# end of mbedTLS
+
+#
+# mDNS
+#
+CONFIG_MDNS_MAX_SERVICES=10
+CONFIG_MDNS_TASK_PRIORITY=1
+CONFIG_MDNS_TASK_STACK_SIZE=4096
+# CONFIG_MDNS_TASK_AFFINITY_NO_AFFINITY is not set
+CONFIG_MDNS_TASK_AFFINITY_CPU0=y
+CONFIG_MDNS_TASK_AFFINITY=0x0
+CONFIG_MDNS_SERVICE_ADD_TIMEOUT_MS=2000
+# CONFIG_MDNS_STRICT_MODE is not set
+CONFIG_MDNS_TIMER_PERIOD_MS=100
+# CONFIG_MDNS_NETWORKING_SOCKET is not set
+CONFIG_MDNS_MULTIPLE_INSTANCE=y
+# end of mDNS
+
+#
+# ESP-MQTT Configurations
+#
+CONFIG_MQTT_PROTOCOL_311=y
+CONFIG_MQTT_TRANSPORT_SSL=y
+CONFIG_MQTT_TRANSPORT_WEBSOCKET=y
+CONFIG_MQTT_TRANSPORT_WEBSOCKET_SECURE=y
+# CONFIG_MQTT_MSG_ID_INCREMENTAL is not set
+# CONFIG_MQTT_SKIP_PUBLISH_IF_DISCONNECTED is not set
+# CONFIG_MQTT_REPORT_DELETED_MESSAGES is not set
+# CONFIG_MQTT_USE_CUSTOM_CONFIG is not set
+# CONFIG_MQTT_TASK_CORE_SELECTION_ENABLED is not set
+# CONFIG_MQTT_CUSTOM_OUTBOX is not set
+# end of ESP-MQTT Configurations
+
+#
+# Newlib
+#
+CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF=y
+# CONFIG_NEWLIB_STDOUT_LINE_ENDING_LF is not set
+# CONFIG_NEWLIB_STDOUT_LINE_ENDING_CR is not set
+# CONFIG_NEWLIB_STDIN_LINE_ENDING_CRLF is not set
+# CONFIG_NEWLIB_STDIN_LINE_ENDING_LF is not set
+CONFIG_NEWLIB_STDIN_LINE_ENDING_CR=y
+# CONFIG_NEWLIB_NANO_FORMAT is not set
+# end of Newlib
+
+#
+# NVS
+#
+# CONFIG_NVS_ASSERT_ERROR_CHECK is not set
+# end of NVS
+
+#
+# OpenSSL
+#
+# CONFIG_OPENSSL_DEBUG is not set
+CONFIG_OPENSSL_ERROR_STACK=y
+# CONFIG_OPENSSL_ASSERT_DO_NOTHING is not set
+CONFIG_OPENSSL_ASSERT_EXIT=y
+# end of OpenSSL
+
+#
+# OpenThread
+#
+# CONFIG_OPENTHREAD_ENABLED is not set
+# end of OpenThread
+
+#
+# PThreads
+#
+CONFIG_PTHREAD_TASK_PRIO_DEFAULT=5
+CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072
+CONFIG_PTHREAD_STACK_MIN=768
+CONFIG_PTHREAD_TASK_CORE_DEFAULT=-1
+CONFIG_PTHREAD_TASK_NAME_DEFAULT="pthread"
+# end of PThreads
+
+#
+# SPI Flash driver
+#
+# CONFIG_SPI_FLASH_VERIFY_WRITE is not set
+# CONFIG_SPI_FLASH_ENABLE_COUNTERS is not set
+CONFIG_SPI_FLASH_ROM_DRIVER_PATCH=y
+CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS=y
+# CONFIG_SPI_FLASH_DANGEROUS_WRITE_FAILS is not set
+# CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED is not set
+# CONFIG_SPI_FLASH_USE_LEGACY_IMPL is not set
+# CONFIG_SPI_FLASH_BYPASS_BLOCK_ERASE is not set
+CONFIG_SPI_FLASH_YIELD_DURING_ERASE=y
+CONFIG_SPI_FLASH_ERASE_YIELD_DURATION_MS=20
+CONFIG_SPI_FLASH_ERASE_YIELD_TICKS=1
+CONFIG_SPI_FLASH_WRITE_CHUNK_SIZE=8192
+# CONFIG_SPI_FLASH_SIZE_OVERRIDE is not set
+# CONFIG_SPI_FLASH_CHECK_ERASE_TIMEOUT_DISABLED is not set
+# CONFIG_SPI_FLASH_OVERRIDE_CHIP_DRIVER_LIST is not set
+
+#
+# Auto-detect flash chips
+#
+CONFIG_SPI_FLASH_SUPPORT_ISSI_CHIP=y
+CONFIG_SPI_FLASH_SUPPORT_MXIC_CHIP=y
+CONFIG_SPI_FLASH_SUPPORT_GD_CHIP=y
+CONFIG_SPI_FLASH_SUPPORT_WINBOND_CHIP=y
+CONFIG_SPI_FLASH_SUPPORT_BOYA_CHIP=y
+CONFIG_SPI_FLASH_SUPPORT_TH_CHIP=y
+# end of Auto-detect flash chips
+
+CONFIG_SPI_FLASH_ENABLE_ENCRYPTED_READ_WRITE=y
+# end of SPI Flash driver
+
+#
+# SPIFFS Configuration
+#
+CONFIG_SPIFFS_MAX_PARTITIONS=3
+
+#
+# SPIFFS Cache Configuration
+#
+CONFIG_SPIFFS_CACHE=y
+CONFIG_SPIFFS_CACHE_WR=y
+# CONFIG_SPIFFS_CACHE_STATS is not set
+# end of SPIFFS Cache Configuration
+
+CONFIG_SPIFFS_PAGE_CHECK=y
+CONFIG_SPIFFS_GC_MAX_RUNS=10
+# CONFIG_SPIFFS_GC_STATS is not set
+CONFIG_SPIFFS_PAGE_SIZE=256
+CONFIG_SPIFFS_OBJ_NAME_LEN=32
+# CONFIG_SPIFFS_FOLLOW_SYMLINKS is not set
+CONFIG_SPIFFS_USE_MAGIC=y
+CONFIG_SPIFFS_USE_MAGIC_LENGTH=y
+CONFIG_SPIFFS_META_LENGTH=4
+CONFIG_SPIFFS_USE_MTIME=y
+
+#
+# Debug Configuration
+#
+# CONFIG_SPIFFS_DBG is not set
+# CONFIG_SPIFFS_API_DBG is not set
+# CONFIG_SPIFFS_GC_DBG is not set
+# CONFIG_SPIFFS_CACHE_DBG is not set
+# CONFIG_SPIFFS_CHECK_DBG is not set
+# CONFIG_SPIFFS_TEST_VISUALISATION is not set
+# end of Debug Configuration
+# end of SPIFFS Configuration
+
+#
+# TCP Transport
+#
+
+#
+# Websocket
+#
+CONFIG_WS_TRANSPORT=y
+CONFIG_WS_BUFFER_SIZE=1024
+# end of Websocket
+# end of TCP Transport
+
+#
+# TinyUSB Stack
+#
+# CONFIG_TINYUSB is not set
+# end of TinyUSB Stack
+
+#
+# Unity unit testing library
+#
+CONFIG_UNITY_ENABLE_FLOAT=y
+CONFIG_UNITY_ENABLE_DOUBLE=y
+# CONFIG_UNITY_ENABLE_64BIT is not set
+# CONFIG_UNITY_ENABLE_COLOR is not set
+CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
+# CONFIG_UNITY_ENABLE_FIXTURE is not set
+# CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL is not set
+# end of Unity unit testing library
+
+#
+# USB-OTG
+#
+CONFIG_USB_OTG_SUPPORTED=y
+CONFIG_USB_HOST_CONTROL_TRANSFER_MAX_SIZE=256
+CONFIG_USB_HOST_HW_BUFFER_BIAS_BALANCED=y
+# CONFIG_USB_HOST_HW_BUFFER_BIAS_IN is not set
+# CONFIG_USB_HOST_HW_BUFFER_BIAS_PERIODIC_OUT is not set
+# end of USB-OTG
+
+#
+# Virtual file system
+#
+CONFIG_VFS_SUPPORT_IO=y
+CONFIG_VFS_SUPPORT_DIR=y
+CONFIG_VFS_SUPPORT_SELECT=y
+CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT=y
+CONFIG_VFS_SUPPORT_TERMIOS=y
+
+#
+# Host File System I/O (Semihosting)
+#
+CONFIG_VFS_SEMIHOSTFS_MAX_MOUNT_POINTS=1
+# end of Host File System I/O (Semihosting)
+# end of Virtual file system
+
+#
+# Wear Levelling
+#
+# CONFIG_WL_SECTOR_SIZE_512 is not set
+CONFIG_WL_SECTOR_SIZE_4096=y
+CONFIG_WL_SECTOR_SIZE=4096
+# end of Wear Levelling
+
+#
+# Wi-Fi Provisioning Manager
+#
+CONFIG_WIFI_PROV_SCAN_MAX_ENTRIES=16
+CONFIG_WIFI_PROV_AUTOSTOP_TIMEOUT=30
+CONFIG_WIFI_PROV_BLE_FORCE_ENCRYPTION=y
+# end of Wi-Fi Provisioning Manager
+
+#
+# Supplicant
+#
+CONFIG_WPA_MBEDTLS_CRYPTO=y
+# CONFIG_WPA_WAPI_PSK is not set
+# CONFIG_WPA_SUITE_B_192 is not set
+# CONFIG_WPA_DEBUG_PRINT is not set
+# CONFIG_WPA_TESTING_OPTIONS is not set
+# CONFIG_WPA_WPS_STRICT is not set
+# CONFIG_WPA_11KV_SUPPORT is not set
+# CONFIG_WPA_MBO_SUPPORT is not set
+# CONFIG_WPA_DPP_SUPPORT is not set
+# end of Supplicant
+# end of Component config
+
+#
+# Compatibility options
+#
+# CONFIG_LEGACY_INCLUDE_COMMON_HEADERS is not set
+# end of Compatibility options
+
+# Deprecated options for backward compatibility
+CONFIG_TOOLPREFIX="xtensa-esp32s2-elf-"
+# CONFIG_LOG_BOOTLOADER_LEVEL_NONE is not set
+# CONFIG_LOG_BOOTLOADER_LEVEL_ERROR is not set
+# CONFIG_LOG_BOOTLOADER_LEVEL_WARN is not set
+CONFIG_LOG_BOOTLOADER_LEVEL_INFO=y
+# CONFIG_LOG_BOOTLOADER_LEVEL_DEBUG is not set
+# CONFIG_LOG_BOOTLOADER_LEVEL_VERBOSE is not set
+CONFIG_LOG_BOOTLOADER_LEVEL=3
+# CONFIG_APP_ROLLBACK_ENABLE is not set
+# CONFIG_FLASH_ENCRYPTION_ENABLED is not set
+# CONFIG_FLASHMODE_QIO is not set
+# CONFIG_FLASHMODE_QOUT is not set
+CONFIG_FLASHMODE_DIO=y
+# CONFIG_FLASHMODE_DOUT is not set
+# CONFIG_MONITOR_BAUD_9600B is not set
+# CONFIG_MONITOR_BAUD_57600B is not set
+CONFIG_MONITOR_BAUD_115200B=y
+# CONFIG_MONITOR_BAUD_230400B is not set
+# CONFIG_MONITOR_BAUD_921600B is not set
+# CONFIG_MONITOR_BAUD_2MB is not set
+# CONFIG_MONITOR_BAUD_OTHER is not set
+CONFIG_MONITOR_BAUD_OTHER_VAL=115200
+CONFIG_MONITOR_BAUD=115200
+CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG=y
+# CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE is not set
+CONFIG_OPTIMIZATION_ASSERTIONS_ENABLED=y
+# CONFIG_OPTIMIZATION_ASSERTIONS_SILENT is not set
+# CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED is not set
+CONFIG_OPTIMIZATION_ASSERTION_LEVEL=2
+# CONFIG_CXX_EXCEPTIONS is not set
+CONFIG_STACK_CHECK_NONE=y
+# CONFIG_STACK_CHECK_NORM is not set
+# CONFIG_STACK_CHECK_STRONG is not set
+# CONFIG_STACK_CHECK_ALL is not set
+# CONFIG_WARN_WRITE_STRINGS is not set
+# CONFIG_DISABLE_GCC8_WARNINGS is not set
+# CONFIG_ESP32_APPTRACE_DEST_TRAX is not set
+CONFIG_ESP32_APPTRACE_DEST_NONE=y
+CONFIG_ESP32_APPTRACE_LOCK_ENABLE=y
+CONFIG_ADC2_DISABLE_DAC=y
+# CONFIG_EVENT_LOOP_PROFILING is not set
+CONFIG_POST_EVENTS_FROM_ISR=y
+CONFIG_POST_EVENTS_FROM_IRAM_ISR=y
+CONFIG_ESP_SYSTEM_PD_FLASH=y
+# CONFIG_ESP32C3_LIGHTSLEEP_GPIO_RESET_WORKAROUND is not set
+CONFIG_IPC_TASK_STACK_SIZE=1536
+CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE=y
+# CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION is not set
+CONFIG_ESP32_PHY_MAX_WIFI_TX_POWER=20
+CONFIG_ESP32_PHY_MAX_TX_POWER=20
+# CONFIG_ESP32S2_PANIC_PRINT_HALT is not set
+CONFIG_ESP32S2_PANIC_PRINT_REBOOT=y
+# CONFIG_ESP32S2_PANIC_SILENT_REBOOT is not set
+# CONFIG_ESP32S2_PANIC_GDBSTUB is not set
+CONFIG_ESP32S2_ALLOW_RTC_FAST_MEM_AS_HEAP=y
+CONFIG_ESP32H2_MEMPROT_FEATURE=y
+CONFIG_ESP32H2_MEMPROT_FEATURE_LOCK=y
+CONFIG_SYSTEM_EVENT_QUEUE_SIZE=32
+CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=2304
+CONFIG_MAIN_TASK_STACK_SIZE=3584
+CONFIG_CONSOLE_UART_DEFAULT=y
+# CONFIG_CONSOLE_UART_CUSTOM is not set
+# CONFIG_ESP_CONSOLE_UART_NONE is not set
+CONFIG_CONSOLE_UART=y
+CONFIG_CONSOLE_UART_NUM=0
+CONFIG_CONSOLE_UART_BAUDRATE=115200
+CONFIG_INT_WDT=y
+CONFIG_INT_WDT_TIMEOUT_MS=300
+CONFIG_TASK_WDT=y
+# CONFIG_TASK_WDT_PANIC is not set
+CONFIG_TASK_WDT_TIMEOUT_S=5
+CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0=y
+# CONFIG_ESP32_DEBUG_STUBS_ENABLE is not set
+CONFIG_TIMER_TASK_STACK_SIZE=3584
+# CONFIG_EXTERNAL_COEX_ENABLE is not set
+# CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH is not set
+# CONFIG_ESP32_ENABLE_COREDUMP_TO_UART is not set
+CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE=y
+CONFIG_MB_MASTER_TIMEOUT_MS_RESPOND=150
+CONFIG_MB_MASTER_DELAY_MS_CONVERT=200
+CONFIG_MB_QUEUE_LENGTH=20
+CONFIG_MB_SERIAL_TASK_STACK_SIZE=4096
+CONFIG_MB_SERIAL_BUF_SIZE=256
+CONFIG_MB_SERIAL_TASK_PRIO=10
+CONFIG_MB_CONTROLLER_SLAVE_ID_SUPPORT=y
+CONFIG_MB_CONTROLLER_SLAVE_ID=0x00112233
+CONFIG_MB_CONTROLLER_NOTIFY_TIMEOUT=20
+CONFIG_MB_CONTROLLER_NOTIFY_QUEUE_SIZE=20
+CONFIG_MB_CONTROLLER_STACK_SIZE=4096
+CONFIG_MB_EVENT_QUEUE_TIMEOUT=20
+# CONFIG_MB_TIMER_PORT_ENABLED is not set
+CONFIG_MB_TIMER_GROUP=0
+CONFIG_MB_TIMER_INDEX=0
+# CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK is not set
+CONFIG_TIMER_TASK_PRIORITY=1
+CONFIG_TIMER_TASK_STACK_DEPTH=2048
+CONFIG_TIMER_QUEUE_LENGTH=10
+# CONFIG_L2_TO_L3_COPY is not set
+# CONFIG_USE_ONLY_LWIP_SELECT is not set
+CONFIG_ESP_GRATUITOUS_ARP=y
+CONFIG_GARP_TMR_INTERVAL=60
+CONFIG_TCPIP_RECVMBOX_SIZE=32
+CONFIG_TCP_MAXRTX=12
+CONFIG_TCP_SYNMAXRTX=12
+CONFIG_TCP_MSS=1440
+CONFIG_TCP_MSL=60000
+CONFIG_TCP_SND_BUF_DEFAULT=5744
+CONFIG_TCP_WND_DEFAULT=5744
+CONFIG_TCP_RECVMBOX_SIZE=6
+CONFIG_TCP_QUEUE_OOSEQ=y
+# CONFIG_ESP_TCP_KEEP_CONNECTION_WHEN_IP_CHANGES is not set
+CONFIG_TCP_OVERSIZE_MSS=y
+# CONFIG_TCP_OVERSIZE_QUARTER_MSS is not set
+# CONFIG_TCP_OVERSIZE_DISABLE is not set
+CONFIG_UDP_RECVMBOX_SIZE=6
+CONFIG_TCPIP_TASK_STACK_SIZE=3072
+CONFIG_TCPIP_TASK_AFFINITY_NO_AFFINITY=y
+# CONFIG_TCPIP_TASK_AFFINITY_CPU0 is not set
+CONFIG_TCPIP_TASK_AFFINITY=0x7FFFFFFF
+# CONFIG_PPP_SUPPORT is not set
+CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT=5
+CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072
+CONFIG_ESP32_PTHREAD_STACK_MIN=768
+CONFIG_ESP32_PTHREAD_TASK_CORE_DEFAULT=-1
+CONFIG_ESP32_PTHREAD_TASK_NAME_DEFAULT="pthread"
+CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS=y
+# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_FAILS is not set
+# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ALLOWED is not set
+# CONFIG_USB_ENABLED is not set
+CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT=y
+CONFIG_SUPPORT_TERMIOS=y
+CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS=1
+# End of deprecated options
diff --git a/sdkconfig.old b/sdkconfig.old
new file mode 100644
index 0000000..ba31434
--- /dev/null
+++ b/sdkconfig.old
@@ -0,0 +1,1376 @@
+#
+# Automatically generated file. DO NOT EDIT.
+# Espressif IoT Development Framework (ESP-IDF) Project Configuration
+#
+CONFIG_IDF_CMAKE=y
+CONFIG_IDF_TARGET_ARCH_XTENSA=y
+CONFIG_IDF_TARGET="esp32s2"
+CONFIG_IDF_TARGET_ESP32S2=y
+CONFIG_IDF_FIRMWARE_CHIP_ID=0x0002
+
+#
+# SDK tool configuration
+#
+CONFIG_SDK_TOOLPREFIX="xtensa-esp32s2-elf-"
+# CONFIG_SDK_TOOLCHAIN_SUPPORTS_TIME_WIDE_64_BITS is not set
+# end of SDK tool configuration
+
+#
+# Build type
+#
+CONFIG_APP_BUILD_TYPE_APP_2NDBOOT=y
+# CONFIG_APP_BUILD_TYPE_ELF_RAM is not set
+CONFIG_APP_BUILD_GENERATE_BINARIES=y
+CONFIG_APP_BUILD_BOOTLOADER=y
+CONFIG_APP_BUILD_USE_FLASH_SECTIONS=y
+# end of Build type
+
+#
+# Application manager
+#
+CONFIG_APP_COMPILE_TIME_DATE=y
+# CONFIG_APP_EXCLUDE_PROJECT_VER_VAR is not set
+# CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR is not set
+# CONFIG_APP_PROJECT_VER_FROM_CONFIG is not set
+CONFIG_APP_RETRIEVE_LEN_ELF_SHA=16
+# end of Application manager
+
+#
+# Bootloader config
+#
+CONFIG_BOOTLOADER_OFFSET_IN_FLASH=0x1000
+CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
+# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_DEBUG is not set
+# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_PERF is not set
+# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_NONE is not set
+# CONFIG_BOOTLOADER_LOG_LEVEL_NONE is not set
+# CONFIG_BOOTLOADER_LOG_LEVEL_ERROR is not set
+# CONFIG_BOOTLOADER_LOG_LEVEL_WARN is not set
+CONFIG_BOOTLOADER_LOG_LEVEL_INFO=y
+# CONFIG_BOOTLOADER_LOG_LEVEL_DEBUG is not set
+# CONFIG_BOOTLOADER_LOG_LEVEL_VERBOSE is not set
+CONFIG_BOOTLOADER_LOG_LEVEL=3
+CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_9V=y
+# CONFIG_BOOTLOADER_FACTORY_RESET is not set
+# CONFIG_BOOTLOADER_APP_TEST is not set
+CONFIG_BOOTLOADER_REGION_PROTECTION_ENABLE=y
+CONFIG_BOOTLOADER_WDT_ENABLE=y
+# CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE is not set
+CONFIG_BOOTLOADER_WDT_TIME_MS=9000
+# CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE is not set
+# CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP is not set
+# CONFIG_BOOTLOADER_SKIP_VALIDATE_ON_POWER_ON is not set
+# CONFIG_BOOTLOADER_SKIP_VALIDATE_ALWAYS is not set
+CONFIG_BOOTLOADER_RESERVE_RTC_SIZE=0
+# CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC is not set
+CONFIG_BOOTLOADER_FLASH_XMC_SUPPORT=y
+# end of Bootloader config
+
+#
+# Security features
+#
+CONFIG_SECURE_BOOT_SUPPORTS_RSA=y
+CONFIG_SECURE_TARGET_HAS_SECURE_ROM_DL_MODE=y
+# CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT is not set
+# CONFIG_SECURE_BOOT is not set
+# CONFIG_SECURE_FLASH_ENC_ENABLED is not set
+# end of Security features
+
+#
+# Boot ROM Behavior
+#
+CONFIG_BOOT_ROM_LOG_ALWAYS_ON=y
+# CONFIG_BOOT_ROM_LOG_ALWAYS_OFF is not set
+# CONFIG_BOOT_ROM_LOG_ON_GPIO_HIGH is not set
+# CONFIG_BOOT_ROM_LOG_ON_GPIO_LOW is not set
+# end of Boot ROM Behavior
+
+#
+# Serial flasher config
+#
+CONFIG_ESPTOOLPY_BAUD_OTHER_VAL=115200
+# CONFIG_ESPTOOLPY_NO_STUB is not set
+# CONFIG_ESPTOOLPY_FLASHMODE_QIO is not set
+# CONFIG_ESPTOOLPY_FLASHMODE_QOUT is not set
+CONFIG_ESPTOOLPY_FLASHMODE_DIO=y
+# CONFIG_ESPTOOLPY_FLASHMODE_DOUT is not set
+CONFIG_ESPTOOLPY_FLASH_SAMPLE_MODE_STR=y
+CONFIG_ESPTOOLPY_FLASHMODE="dio"
+CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
+# CONFIG_ESPTOOLPY_FLASHFREQ_40M is not set
+# CONFIG_ESPTOOLPY_FLASHFREQ_26M is not set
+# CONFIG_ESPTOOLPY_FLASHFREQ_20M is not set
+CONFIG_ESPTOOLPY_FLASHFREQ="80m"
+# CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set
+CONFIG_ESPTOOLPY_FLASHSIZE_2MB=y
+# CONFIG_ESPTOOLPY_FLASHSIZE_4MB is not set
+# CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set
+# CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set
+# CONFIG_ESPTOOLPY_FLASHSIZE_32MB is not set
+# CONFIG_ESPTOOLPY_FLASHSIZE_64MB is not set
+# CONFIG_ESPTOOLPY_FLASHSIZE_128MB is not set
+CONFIG_ESPTOOLPY_FLASHSIZE="2MB"
+CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y
+CONFIG_ESPTOOLPY_BEFORE_RESET=y
+# CONFIG_ESPTOOLPY_BEFORE_NORESET is not set
+CONFIG_ESPTOOLPY_BEFORE="default_reset"
+CONFIG_ESPTOOLPY_AFTER_RESET=y
+# CONFIG_ESPTOOLPY_AFTER_NORESET is not set
+CONFIG_ESPTOOLPY_AFTER="hard_reset"
+# CONFIG_ESPTOOLPY_MONITOR_BAUD_CONSOLE is not set
+# CONFIG_ESPTOOLPY_MONITOR_BAUD_9600B is not set
+# CONFIG_ESPTOOLPY_MONITOR_BAUD_57600B is not set
+CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y
+# CONFIG_ESPTOOLPY_MONITOR_BAUD_230400B is not set
+# CONFIG_ESPTOOLPY_MONITOR_BAUD_921600B is not set
+# CONFIG_ESPTOOLPY_MONITOR_BAUD_2MB is not set
+# CONFIG_ESPTOOLPY_MONITOR_BAUD_OTHER is not set
+CONFIG_ESPTOOLPY_MONITOR_BAUD_OTHER_VAL=115200
+CONFIG_ESPTOOLPY_MONITOR_BAUD=115200
+# end of Serial flasher config
+
+#
+# Partition Table
+#
+CONFIG_PARTITION_TABLE_SINGLE_APP=y
+# CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE is not set
+# CONFIG_PARTITION_TABLE_TWO_OTA is not set
+# CONFIG_PARTITION_TABLE_CUSTOM is not set
+CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
+CONFIG_PARTITION_TABLE_FILENAME="partitions_singleapp.csv"
+CONFIG_PARTITION_TABLE_OFFSET=0x8000
+CONFIG_PARTITION_TABLE_MD5=y
+# end of Partition Table
+
+#
+# ST7789 Configuration
+#
+CONFIG_GPIO_RANGE_MAX=46
+CONFIG_WIDTH=240
+CONFIG_HEIGHT=280
+CONFIG_OFFSETX=0
+CONFIG_OFFSETY=0
+CONFIG_MOSI_GPIO=11
+CONFIG_SCLK_GPIO=12
+CONFIG_CS_GPIO=-1
+CONFIG_DC_GPIO=13
+CONFIG_RESET_GPIO=10
+CONFIG_BL_GPIO=14
+# CONFIG_INVERSION is not set
+# CONFIG_SPI2_HOST is not set
+CONFIG_SPI3_HOST=y
+# end of ST7789 Configuration
+
+#
+# Compiler options
+#
+CONFIG_COMPILER_OPTIMIZATION_DEFAULT=y
+# CONFIG_COMPILER_OPTIMIZATION_SIZE is not set
+# CONFIG_COMPILER_OPTIMIZATION_PERF is not set
+# CONFIG_COMPILER_OPTIMIZATION_NONE is not set
+CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y
+# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT is not set
+# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE is not set
+CONFIG_COMPILER_OPTIMIZATION_ASSERTION_LEVEL=2
+# CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT is not set
+CONFIG_COMPILER_HIDE_PATHS_MACROS=y
+# CONFIG_COMPILER_CXX_EXCEPTIONS is not set
+# CONFIG_COMPILER_CXX_RTTI is not set
+CONFIG_COMPILER_STACK_CHECK_MODE_NONE=y
+# CONFIG_COMPILER_STACK_CHECK_MODE_NORM is not set
+# CONFIG_COMPILER_STACK_CHECK_MODE_STRONG is not set
+# CONFIG_COMPILER_STACK_CHECK_MODE_ALL is not set
+# CONFIG_COMPILER_WARN_WRITE_STRINGS is not set
+# CONFIG_COMPILER_DISABLE_GCC8_WARNINGS is not set
+# CONFIG_COMPILER_DUMP_RTL_FILES is not set
+# end of Compiler options
+
+#
+# Component config
+#
+
+#
+# Application Level Tracing
+#
+# CONFIG_APPTRACE_DEST_JTAG is not set
+CONFIG_APPTRACE_DEST_NONE=y
+CONFIG_APPTRACE_LOCK_ENABLE=y
+# end of Application Level Tracing
+
+#
+# ESP-ASIO
+#
+# CONFIG_ASIO_SSL_SUPPORT is not set
+# end of ESP-ASIO
+
+#
+# CoAP Configuration
+#
+CONFIG_COAP_MBEDTLS_PSK=y
+# CONFIG_COAP_MBEDTLS_PKI is not set
+# CONFIG_COAP_MBEDTLS_DEBUG is not set
+CONFIG_COAP_LOG_DEFAULT_LEVEL=0
+# end of CoAP Configuration
+
+#
+# Driver configurations
+#
+
+#
+# ADC configuration
+#
+# CONFIG_ADC_FORCE_XPD_FSM is not set
+CONFIG_ADC_DISABLE_DAC=y
+# end of ADC configuration
+
+#
+# MCPWM configuration
+#
+# CONFIG_MCPWM_ISR_IN_IRAM is not set
+# end of MCPWM configuration
+
+#
+# SPI configuration
+#
+# CONFIG_SPI_MASTER_IN_IRAM is not set
+CONFIG_SPI_MASTER_ISR_IN_IRAM=y
+# CONFIG_SPI_SLAVE_IN_IRAM is not set
+CONFIG_SPI_SLAVE_ISR_IN_IRAM=y
+# end of SPI configuration
+
+#
+# TWAI configuration
+#
+# CONFIG_TWAI_ISR_IN_IRAM is not set
+# end of TWAI configuration
+
+#
+# UART configuration
+#
+# CONFIG_UART_ISR_IN_IRAM is not set
+# end of UART configuration
+
+#
+# GDMA Configuration
+#
+# CONFIG_GDMA_CTRL_FUNC_IN_IRAM is not set
+# CONFIG_GDMA_ISR_IRAM_SAFE is not set
+# end of GDMA Configuration
+# end of Driver configurations
+
+#
+# eFuse Bit Manager
+#
+# CONFIG_EFUSE_CUSTOM_TABLE is not set
+# CONFIG_EFUSE_VIRTUAL is not set
+CONFIG_EFUSE_MAX_BLK_LEN=256
+# end of eFuse Bit Manager
+
+#
+# ESP-TLS
+#
+CONFIG_ESP_TLS_USING_MBEDTLS=y
+CONFIG_ESP_TLS_USE_DS_PERIPHERAL=y
+# CONFIG_ESP_TLS_CLIENT_SESSION_TICKETS is not set
+# CONFIG_ESP_TLS_SERVER is not set
+# CONFIG_ESP_TLS_PSK_VERIFICATION is not set
+# CONFIG_ESP_TLS_INSECURE is not set
+# end of ESP-TLS
+
+#
+# ESP32S2-specific
+#
+# CONFIG_ESP32S2_DEFAULT_CPU_FREQ_80 is not set
+CONFIG_ESP32S2_DEFAULT_CPU_FREQ_160=y
+# CONFIG_ESP32S2_DEFAULT_CPU_FREQ_240 is not set
+CONFIG_ESP32S2_DEFAULT_CPU_FREQ_MHZ=160
+
+#
+# Cache config
+#
+CONFIG_ESP32S2_INSTRUCTION_CACHE_8KB=y
+# CONFIG_ESP32S2_INSTRUCTION_CACHE_16KB is not set
+# CONFIG_ESP32S2_INSTRUCTION_CACHE_LINE_16B is not set
+CONFIG_ESP32S2_INSTRUCTION_CACHE_LINE_32B=y
+CONFIG_ESP32S2_DATA_CACHE_0KB=y
+# CONFIG_ESP32S2_DATA_CACHE_8KB is not set
+# CONFIG_ESP32S2_DATA_CACHE_16KB is not set
+# CONFIG_ESP32S2_DATA_CACHE_LINE_16B is not set
+CONFIG_ESP32S2_DATA_CACHE_LINE_32B=y
+# CONFIG_ESP32S2_INSTRUCTION_CACHE_WRAP is not set
+# CONFIG_ESP32S2_DATA_CACHE_WRAP is not set
+# end of Cache config
+
+# CONFIG_ESP32S2_SPIRAM_SUPPORT is not set
+# CONFIG_ESP32S2_TRAX is not set
+CONFIG_ESP32S2_TRACEMEM_RESERVE_DRAM=0x0
+# CONFIG_ESP32S2_ULP_COPROC_ENABLED is not set
+CONFIG_ESP32S2_ULP_COPROC_RESERVE_MEM=0
+CONFIG_ESP32S2_DEBUG_OCDAWARE=y
+CONFIG_ESP32S2_BROWNOUT_DET=y
+CONFIG_ESP32S2_BROWNOUT_DET_LVL_SEL_7=y
+# CONFIG_ESP32S2_BROWNOUT_DET_LVL_SEL_6 is not set
+# CONFIG_ESP32S2_BROWNOUT_DET_LVL_SEL_5 is not set
+# CONFIG_ESP32S2_BROWNOUT_DET_LVL_SEL_4 is not set
+# CONFIG_ESP32S2_BROWNOUT_DET_LVL_SEL_3 is not set
+# CONFIG_ESP32S2_BROWNOUT_DET_LVL_SEL_2 is not set
+# CONFIG_ESP32S2_BROWNOUT_DET_LVL_SEL_1 is not set
+CONFIG_ESP32S2_BROWNOUT_DET_LVL=7
+CONFIG_ESP32S2_TIME_SYSCALL_USE_RTC_FRC1=y
+# CONFIG_ESP32S2_TIME_SYSCALL_USE_RTC is not set
+# CONFIG_ESP32S2_TIME_SYSCALL_USE_FRC1 is not set
+# CONFIG_ESP32S2_TIME_SYSCALL_USE_NONE is not set
+CONFIG_ESP32S2_RTC_CLK_SRC_INT_RC=y
+# CONFIG_ESP32S2_RTC_CLK_SRC_EXT_CRYS is not set
+# CONFIG_ESP32S2_RTC_CLK_SRC_EXT_OSC is not set
+# CONFIG_ESP32S2_RTC_CLK_SRC_INT_8MD256 is not set
+CONFIG_ESP32S2_RTC_CLK_CAL_CYCLES=576
+# CONFIG_ESP32S2_NO_BLOBS is not set
+# CONFIG_ESP32S2_KEEP_USB_ALIVE is not set
+# CONFIG_ESP32S2_RTCDATA_IN_FAST_MEM is not set
+# CONFIG_ESP32S2_USE_FIXED_STATIC_RAM_SIZE is not set
+# end of ESP32S2-specific
+
+#
+# ADC-Calibration
+#
+# end of ADC-Calibration
+
+#
+# Common ESP-related
+#
+CONFIG_ESP_ERR_TO_NAME_LOOKUP=y
+# end of Common ESP-related
+
+#
+# Ethernet
+#
+CONFIG_ETH_ENABLED=y
+CONFIG_ETH_USE_SPI_ETHERNET=y
+# CONFIG_ETH_SPI_ETHERNET_DM9051 is not set
+# CONFIG_ETH_SPI_ETHERNET_W5500 is not set
+# CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL is not set
+# CONFIG_ETH_USE_OPENETH is not set
+# end of Ethernet
+
+#
+# Event Loop Library
+#
+# CONFIG_ESP_EVENT_LOOP_PROFILING is not set
+CONFIG_ESP_EVENT_POST_FROM_ISR=y
+CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR=y
+# end of Event Loop Library
+
+#
+# GDB Stub
+#
+# end of GDB Stub
+
+#
+# ESP HTTP client
+#
+CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y
+# CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH is not set
+CONFIG_ESP_HTTP_CLIENT_ENABLE_DIGEST_AUTH=y
+# end of ESP HTTP client
+
+#
+# HTTP Server
+#
+CONFIG_HTTPD_MAX_REQ_HDR_LEN=512
+CONFIG_HTTPD_MAX_URI_LEN=512
+CONFIG_HTTPD_ERR_RESP_NO_DELAY=y
+CONFIG_HTTPD_PURGE_BUF_LEN=32
+# CONFIG_HTTPD_LOG_PURGE_DATA is not set
+# CONFIG_HTTPD_WS_SUPPORT is not set
+# end of HTTP Server
+
+#
+# ESP HTTPS OTA
+#
+# CONFIG_OTA_ALLOW_HTTP is not set
+# end of ESP HTTPS OTA
+
+#
+# ESP HTTPS server
+#
+# CONFIG_ESP_HTTPS_SERVER_ENABLE is not set
+# end of ESP HTTPS server
+
+#
+# Hardware Settings
+#
+
+#
+# MAC Config
+#
+CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_STA=y
+CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_AP=y
+# CONFIG_ESP32S2_UNIVERSAL_MAC_ADDRESSES_ONE is not set
+CONFIG_ESP32S2_UNIVERSAL_MAC_ADDRESSES_TWO=y
+CONFIG_ESP32S2_UNIVERSAL_MAC_ADDRESSES=2
+# end of MAC Config
+
+#
+# Sleep Config
+#
+CONFIG_ESP_SLEEP_POWER_DOWN_FLASH=y
+CONFIG_ESP_SLEEP_RTC_BUS_ISO_WORKAROUND=y
+# CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND is not set
+# CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND is not set
+# end of Sleep Config
+
+#
+# RTC Clock Config
+#
+# end of RTC Clock Config
+# end of Hardware Settings
+
+#
+# IPC (Inter-Processor Call)
+#
+CONFIG_ESP_IPC_TASK_STACK_SIZE=1536
+# end of IPC (Inter-Processor Call)
+
+#
+# LCD and Touch Panel
+#
+
+#
+# LCD Peripheral Configuration
+#
+CONFIG_LCD_PANEL_IO_FORMAT_BUF_SIZE=32
+# end of LCD Peripheral Configuration
+# end of LCD and Touch Panel
+
+#
+# ESP NETIF Adapter
+#
+CONFIG_ESP_NETIF_IP_LOST_TIMER_INTERVAL=120
+CONFIG_ESP_NETIF_TCPIP_LWIP=y
+# CONFIG_ESP_NETIF_LOOPBACK is not set
+CONFIG_ESP_NETIF_TCPIP_ADAPTER_COMPATIBLE_LAYER=y
+# end of ESP NETIF Adapter
+
+#
+# PHY
+#
+CONFIG_ESP_PHY_CALIBRATION_AND_DATA_STORAGE=y
+# CONFIG_ESP_PHY_INIT_DATA_IN_PARTITION is not set
+CONFIG_ESP_PHY_MAX_WIFI_TX_POWER=20
+CONFIG_ESP_PHY_MAX_TX_POWER=20
+# CONFIG_ESP_PHY_ENABLE_USB is not set
+# end of PHY
+
+#
+# Power Management
+#
+# CONFIG_PM_ENABLE is not set
+# end of Power Management
+
+#
+# ESP System Settings
+#
+# CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT is not set
+CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT=y
+# CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT is not set
+# CONFIG_ESP_SYSTEM_PANIC_GDBSTUB is not set
+# CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME is not set
+CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE=y
+CONFIG_ESP_SYSTEM_RTC_FAST_MEM_AS_HEAP_DEPCHECK=y
+CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP=y
+
+#
+# Memory protection
+#
+CONFIG_ESP_SYSTEM_MEMPROT_DEPCHECK=y
+CONFIG_ESP_SYSTEM_MEMPROT_FEATURE=y
+CONFIG_ESP_SYSTEM_MEMPROT_FEATURE_LOCK=y
+CONFIG_ESP_SYSTEM_MEMPROT_CPU_PREFETCH_PAD_SIZE=16
+CONFIG_ESP_SYSTEM_MEMPROT_MEM_ALIGN_SIZE=4
+# end of Memory protection
+
+CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE=32
+CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=2304
+CONFIG_ESP_MAIN_TASK_STACK_SIZE=3584
+CONFIG_ESP_MAIN_TASK_AFFINITY_CPU0=y
+# CONFIG_ESP_MAIN_TASK_AFFINITY_NO_AFFINITY is not set
+CONFIG_ESP_MAIN_TASK_AFFINITY=0x0
+CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE=2048
+CONFIG_ESP_CONSOLE_UART_DEFAULT=y
+# CONFIG_ESP_CONSOLE_USB_CDC is not set
+# CONFIG_ESP_CONSOLE_UART_CUSTOM is not set
+# CONFIG_ESP_CONSOLE_NONE is not set
+CONFIG_ESP_CONSOLE_UART=y
+CONFIG_ESP_CONSOLE_MULTIPLE_UART=y
+CONFIG_ESP_CONSOLE_UART_NUM=0
+CONFIG_ESP_CONSOLE_UART_BAUDRATE=115200
+CONFIG_ESP_INT_WDT=y
+CONFIG_ESP_INT_WDT_TIMEOUT_MS=300
+CONFIG_ESP_TASK_WDT=y
+# CONFIG_ESP_TASK_WDT_PANIC is not set
+CONFIG_ESP_TASK_WDT_TIMEOUT_S=5
+CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0=y
+# CONFIG_ESP_PANIC_HANDLER_IRAM is not set
+# CONFIG_ESP_DEBUG_STUBS_ENABLE is not set
+CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_4=y
+# end of ESP System Settings
+
+#
+# High resolution timer (esp_timer)
+#
+# CONFIG_ESP_TIMER_PROFILING is not set
+CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER=y
+CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER=y
+CONFIG_ESP_TIMER_TASK_STACK_SIZE=3584
+CONFIG_ESP_TIMER_INTERRUPT_LEVEL=1
+# CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD is not set
+CONFIG_ESP_TIMER_IMPL_SYSTIMER=y
+# end of High resolution timer (esp_timer)
+
+#
+# Wi-Fi
+#
+CONFIG_ESP32_WIFI_ENABLED=y
+CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=10
+CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=32
+# CONFIG_ESP32_WIFI_STATIC_TX_BUFFER is not set
+CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER=y
+CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=1
+CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM=32
+# CONFIG_ESP32_WIFI_CSI_ENABLED is not set
+CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED=y
+CONFIG_ESP32_WIFI_TX_BA_WIN=6
+CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED=y
+CONFIG_ESP32_WIFI_RX_BA_WIN=6
+CONFIG_ESP32_WIFI_NVS_ENABLED=y
+CONFIG_ESP32_WIFI_SOFTAP_BEACON_MAX_LEN=752
+CONFIG_ESP32_WIFI_MGMT_SBUF_NUM=32
+CONFIG_ESP32_WIFI_IRAM_OPT=y
+CONFIG_ESP32_WIFI_RX_IRAM_OPT=y
+CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE=y
+# CONFIG_ESP_WIFI_SLP_IRAM_OPT is not set
+# CONFIG_ESP_WIFI_FTM_ENABLE is not set
+# CONFIG_ESP_WIFI_STA_DISCONNECTED_PM_ENABLE is not set
+# CONFIG_ESP_WIFI_EXTERNAL_COEXIST_ENABLE is not set
+# CONFIG_ESP_WIFI_GMAC_SUPPORT is not set
+CONFIG_ESP_WIFI_SOFTAP_SUPPORT=y
+# end of Wi-Fi
+
+#
+# Core dump
+#
+# CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH is not set
+# CONFIG_ESP_COREDUMP_ENABLE_TO_UART is not set
+CONFIG_ESP_COREDUMP_ENABLE_TO_NONE=y
+# end of Core dump
+
+#
+# FAT Filesystem support
+#
+# CONFIG_FATFS_CODEPAGE_DYNAMIC is not set
+CONFIG_FATFS_CODEPAGE_437=y
+# CONFIG_FATFS_CODEPAGE_720 is not set
+# CONFIG_FATFS_CODEPAGE_737 is not set
+# CONFIG_FATFS_CODEPAGE_771 is not set
+# CONFIG_FATFS_CODEPAGE_775 is not set
+# CONFIG_FATFS_CODEPAGE_850 is not set
+# CONFIG_FATFS_CODEPAGE_852 is not set
+# CONFIG_FATFS_CODEPAGE_855 is not set
+# CONFIG_FATFS_CODEPAGE_857 is not set
+# CONFIG_FATFS_CODEPAGE_860 is not set
+# CONFIG_FATFS_CODEPAGE_861 is not set
+# CONFIG_FATFS_CODEPAGE_862 is not set
+# CONFIG_FATFS_CODEPAGE_863 is not set
+# CONFIG_FATFS_CODEPAGE_864 is not set
+# CONFIG_FATFS_CODEPAGE_865 is not set
+# CONFIG_FATFS_CODEPAGE_866 is not set
+# CONFIG_FATFS_CODEPAGE_869 is not set
+# CONFIG_FATFS_CODEPAGE_932 is not set
+# CONFIG_FATFS_CODEPAGE_936 is not set
+# CONFIG_FATFS_CODEPAGE_949 is not set
+# CONFIG_FATFS_CODEPAGE_950 is not set
+CONFIG_FATFS_CODEPAGE=437
+CONFIG_FATFS_LFN_NONE=y
+# CONFIG_FATFS_LFN_HEAP is not set
+# CONFIG_FATFS_LFN_STACK is not set
+CONFIG_FATFS_FS_LOCK=0
+CONFIG_FATFS_TIMEOUT_MS=10000
+CONFIG_FATFS_PER_FILE_CACHE=y
+# CONFIG_FATFS_USE_FASTSEEK is not set
+# end of FAT Filesystem support
+
+#
+# Modbus configuration
+#
+CONFIG_FMB_COMM_MODE_TCP_EN=y
+CONFIG_FMB_TCP_PORT_DEFAULT=502
+CONFIG_FMB_TCP_PORT_MAX_CONN=5
+CONFIG_FMB_TCP_CONNECTION_TOUT_SEC=20
+CONFIG_FMB_COMM_MODE_RTU_EN=y
+CONFIG_FMB_COMM_MODE_ASCII_EN=y
+CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND=150
+CONFIG_FMB_MASTER_DELAY_MS_CONVERT=200
+CONFIG_FMB_QUEUE_LENGTH=20
+CONFIG_FMB_PORT_TASK_STACK_SIZE=4096
+CONFIG_FMB_SERIAL_BUF_SIZE=256
+CONFIG_FMB_SERIAL_ASCII_BITS_PER_SYMB=8
+CONFIG_FMB_SERIAL_ASCII_TIMEOUT_RESPOND_MS=1000
+CONFIG_FMB_PORT_TASK_PRIO=10
+CONFIG_FMB_PORT_TASK_AFFINITY=0x7FFFFFFF
+CONFIG_FMB_CONTROLLER_SLAVE_ID_SUPPORT=y
+CONFIG_FMB_CONTROLLER_SLAVE_ID=0x00112233
+CONFIG_FMB_CONTROLLER_NOTIFY_TIMEOUT=20
+CONFIG_FMB_CONTROLLER_NOTIFY_QUEUE_SIZE=20
+CONFIG_FMB_CONTROLLER_STACK_SIZE=4096
+CONFIG_FMB_EVENT_QUEUE_TIMEOUT=20
+# CONFIG_FMB_TIMER_PORT_ENABLED is not set
+CONFIG_FMB_TIMER_GROUP=0
+CONFIG_FMB_TIMER_INDEX=0
+CONFIG_FMB_MASTER_TIMER_GROUP=0
+CONFIG_FMB_MASTER_TIMER_INDEX=0
+# CONFIG_FMB_TIMER_ISR_IN_IRAM is not set
+# end of Modbus configuration
+
+#
+# FreeRTOS
+#
+CONFIG_FREERTOS_UNICORE=y
+CONFIG_FREERTOS_NO_AFFINITY=0x7FFFFFFF
+CONFIG_FREERTOS_TICK_SUPPORT_CORETIMER=y
+CONFIG_FREERTOS_CORETIMER_0=y
+# CONFIG_FREERTOS_CORETIMER_1 is not set
+CONFIG_FREERTOS_SYSTICK_USES_CCOUNT=y
+CONFIG_FREERTOS_OPTIMIZED_SCHEDULER=y
+CONFIG_FREERTOS_HZ=100
+CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION=y
+# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE is not set
+# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_PTRVAL is not set
+CONFIG_FREERTOS_CHECK_STACKOVERFLOW_CANARY=y
+# CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK is not set
+CONFIG_FREERTOS_INTERRUPT_BACKTRACE=y
+CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=1
+CONFIG_FREERTOS_ASSERT_FAIL_ABORT=y
+# CONFIG_FREERTOS_ASSERT_FAIL_PRINT_CONTINUE is not set
+# CONFIG_FREERTOS_ASSERT_DISABLE is not set
+CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1536
+CONFIG_FREERTOS_ISR_STACKSIZE=1536
+# CONFIG_FREERTOS_LEGACY_HOOKS is not set
+CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16
+CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y
+# CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP is not set
+CONFIG_FREERTOS_TIMER_TASK_PRIORITY=1
+CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=2048
+CONFIG_FREERTOS_TIMER_QUEUE_LENGTH=10
+CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=0
+CONFIG_FREERTOS_USE_TRACE_FACILITY=y
+CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS=y
+# CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID is not set
+CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=y
+CONFIG_FREERTOS_RUN_TIME_STATS_USING_ESP_TIMER=y
+# CONFIG_FREERTOS_RUN_TIME_STATS_USING_CPU_CLK is not set
+CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER=y
+CONFIG_FREERTOS_CHECK_MUTEX_GIVEN_BY_OWNER=y
+# CONFIG_FREERTOS_CHECK_PORT_CRITICAL_COMPLIANCE is not set
+# CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH is not set
+CONFIG_FREERTOS_DEBUG_OCDAWARE=y
+CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT=y
+# CONFIG_FREERTOS_PLACE_SNAPSHOT_FUNS_INTO_FLASH is not set
+# end of FreeRTOS
+
+#
+# Hardware Abstraction Layer (HAL) and Low Level (LL)
+#
+CONFIG_HAL_ASSERTION_EQUALS_SYSTEM=y
+# CONFIG_HAL_ASSERTION_DISABLE is not set
+# CONFIG_HAL_ASSERTION_SILIENT is not set
+# CONFIG_HAL_ASSERTION_ENABLE is not set
+CONFIG_HAL_DEFAULT_ASSERTION_LEVEL=2
+# end of Hardware Abstraction Layer (HAL) and Low Level (LL)
+
+#
+# Heap memory debugging
+#
+CONFIG_HEAP_POISONING_DISABLED=y
+# CONFIG_HEAP_POISONING_LIGHT is not set
+# CONFIG_HEAP_POISONING_COMPREHENSIVE is not set
+CONFIG_HEAP_TRACING_OFF=y
+# CONFIG_HEAP_TRACING_STANDALONE is not set
+# CONFIG_HEAP_TRACING_TOHOST is not set
+# CONFIG_HEAP_ABORT_WHEN_ALLOCATION_FAILS is not set
+# end of Heap memory debugging
+
+#
+# jsmn
+#
+# CONFIG_JSMN_PARENT_LINKS is not set
+# CONFIG_JSMN_STRICT is not set
+# end of jsmn
+
+#
+# libsodium
+#
+# end of libsodium
+
+#
+# Log output
+#
+# CONFIG_LOG_DEFAULT_LEVEL_NONE is not set
+# CONFIG_LOG_DEFAULT_LEVEL_ERROR is not set
+# CONFIG_LOG_DEFAULT_LEVEL_WARN is not set
+CONFIG_LOG_DEFAULT_LEVEL_INFO=y
+# CONFIG_LOG_DEFAULT_LEVEL_DEBUG is not set
+# CONFIG_LOG_DEFAULT_LEVEL_VERBOSE is not set
+CONFIG_LOG_DEFAULT_LEVEL=3
+CONFIG_LOG_MAXIMUM_EQUALS_DEFAULT=y
+# CONFIG_LOG_MAXIMUM_LEVEL_DEBUG is not set
+# CONFIG_LOG_MAXIMUM_LEVEL_VERBOSE is not set
+CONFIG_LOG_MAXIMUM_LEVEL=3
+CONFIG_LOG_COLORS=y
+CONFIG_LOG_TIMESTAMP_SOURCE_RTOS=y
+# CONFIG_LOG_TIMESTAMP_SOURCE_SYSTEM is not set
+# end of Log output
+
+#
+# LWIP
+#
+CONFIG_LWIP_LOCAL_HOSTNAME="espressif"
+# CONFIG_LWIP_NETIF_API is not set
+# CONFIG_LWIP_TCPIP_CORE_LOCKING is not set
+CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=y
+# CONFIG_LWIP_L2_TO_L3_COPY is not set
+# CONFIG_LWIP_IRAM_OPTIMIZATION is not set
+CONFIG_LWIP_TIMERS_ONDEMAND=y
+CONFIG_LWIP_MAX_SOCKETS=10
+# CONFIG_LWIP_USE_ONLY_LWIP_SELECT is not set
+# CONFIG_LWIP_SO_LINGER is not set
+CONFIG_LWIP_SO_REUSE=y
+CONFIG_LWIP_SO_REUSE_RXTOALL=y
+# CONFIG_LWIP_SO_RCVBUF is not set
+# CONFIG_LWIP_NETBUF_RECVINFO is not set
+CONFIG_LWIP_IP4_FRAG=y
+CONFIG_LWIP_IP6_FRAG=y
+# CONFIG_LWIP_IP4_REASSEMBLY is not set
+# CONFIG_LWIP_IP6_REASSEMBLY is not set
+# CONFIG_LWIP_IP_FORWARD is not set
+# CONFIG_LWIP_STATS is not set
+# CONFIG_LWIP_ETHARP_TRUST_IP_MAC is not set
+CONFIG_LWIP_ESP_GRATUITOUS_ARP=y
+CONFIG_LWIP_GARP_TMR_INTERVAL=60
+CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=32
+CONFIG_LWIP_DHCP_DOES_ARP_CHECK=y
+# CONFIG_LWIP_DHCP_DISABLE_CLIENT_ID is not set
+CONFIG_LWIP_DHCP_DISABLE_VENDOR_CLASS_ID=y
+# CONFIG_LWIP_DHCP_RESTORE_LAST_IP is not set
+CONFIG_LWIP_DHCP_OPTIONS_LEN=68
+
+#
+# DHCP server
+#
+CONFIG_LWIP_DHCPS=y
+CONFIG_LWIP_DHCPS_LEASE_UNIT=60
+CONFIG_LWIP_DHCPS_MAX_STATION_NUM=8
+# end of DHCP server
+
+# CONFIG_LWIP_AUTOIP is not set
+CONFIG_LWIP_IPV6=y
+# CONFIG_LWIP_IPV6_AUTOCONFIG is not set
+CONFIG_LWIP_IPV6_NUM_ADDRESSES=3
+# CONFIG_LWIP_IPV6_FORWARD is not set
+# CONFIG_LWIP_NETIF_STATUS_CALLBACK is not set
+CONFIG_LWIP_NETIF_LOOPBACK=y
+CONFIG_LWIP_LOOPBACK_MAX_PBUFS=8
+
+#
+# TCP
+#
+CONFIG_LWIP_MAX_ACTIVE_TCP=16
+CONFIG_LWIP_MAX_LISTENING_TCP=16
+CONFIG_LWIP_TCP_HIGH_SPEED_RETRANSMISSION=y
+CONFIG_LWIP_TCP_MAXRTX=12
+CONFIG_LWIP_TCP_SYNMAXRTX=12
+CONFIG_LWIP_TCP_MSS=1440
+CONFIG_LWIP_TCP_TMR_INTERVAL=250
+CONFIG_LWIP_TCP_MSL=60000
+CONFIG_LWIP_TCP_SND_BUF_DEFAULT=5744
+CONFIG_LWIP_TCP_WND_DEFAULT=5744
+CONFIG_LWIP_TCP_RECVMBOX_SIZE=6
+CONFIG_LWIP_TCP_QUEUE_OOSEQ=y
+# CONFIG_LWIP_TCP_SACK_OUT is not set
+# CONFIG_LWIP_TCP_KEEP_CONNECTION_WHEN_IP_CHANGES is not set
+CONFIG_LWIP_TCP_OVERSIZE_MSS=y
+# CONFIG_LWIP_TCP_OVERSIZE_QUARTER_MSS is not set
+# CONFIG_LWIP_TCP_OVERSIZE_DISABLE is not set
+CONFIG_LWIP_TCP_RTO_TIME=1500
+# end of TCP
+
+#
+# UDP
+#
+CONFIG_LWIP_MAX_UDP_PCBS=16
+CONFIG_LWIP_UDP_RECVMBOX_SIZE=6
+# end of UDP
+
+#
+# Checksums
+#
+# CONFIG_LWIP_CHECKSUM_CHECK_IP is not set
+# CONFIG_LWIP_CHECKSUM_CHECK_UDP is not set
+CONFIG_LWIP_CHECKSUM_CHECK_ICMP=y
+# end of Checksums
+
+CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=3072
+CONFIG_LWIP_TCPIP_TASK_AFFINITY_NO_AFFINITY=y
+# CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU0 is not set
+CONFIG_LWIP_TCPIP_TASK_AFFINITY=0x7FFFFFFF
+# CONFIG_LWIP_PPP_SUPPORT is not set
+CONFIG_LWIP_IPV6_MEMP_NUM_ND6_QUEUE=3
+CONFIG_LWIP_IPV6_ND6_NUM_NEIGHBORS=5
+# CONFIG_LWIP_SLIP_SUPPORT is not set
+
+#
+# ICMP
+#
+CONFIG_LWIP_ICMP=y
+# CONFIG_LWIP_MULTICAST_PING is not set
+# CONFIG_LWIP_BROADCAST_PING is not set
+# end of ICMP
+
+#
+# LWIP RAW API
+#
+CONFIG_LWIP_MAX_RAW_PCBS=16
+# end of LWIP RAW API
+
+#
+# SNTP
+#
+CONFIG_LWIP_SNTP_MAX_SERVERS=1
+# CONFIG_LWIP_DHCP_GET_NTP_SRV is not set
+CONFIG_LWIP_SNTP_UPDATE_DELAY=3600000
+# end of SNTP
+
+CONFIG_LWIP_ESP_LWIP_ASSERT=y
+
+#
+# Hooks
+#
+# CONFIG_LWIP_HOOK_TCP_ISN_NONE is not set
+CONFIG_LWIP_HOOK_TCP_ISN_DEFAULT=y
+# CONFIG_LWIP_HOOK_TCP_ISN_CUSTOM is not set
+CONFIG_LWIP_HOOK_IP6_ROUTE_NONE=y
+# CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT is not set
+# CONFIG_LWIP_HOOK_IP6_ROUTE_CUSTOM is not set
+CONFIG_LWIP_HOOK_ND6_GET_GW_NONE=y
+# CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT is not set
+# CONFIG_LWIP_HOOK_ND6_GET_GW_CUSTOM is not set
+CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_NONE=y
+# CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_DEFAULT is not set
+# CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_CUSTOM is not set
+# end of Hooks
+
+# CONFIG_LWIP_DEBUG is not set
+# end of LWIP
+
+#
+# mbedTLS
+#
+CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
+# CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC is not set
+# CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC is not set
+CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y
+CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN=16384
+CONFIG_MBEDTLS_SSL_OUT_CONTENT_LEN=4096
+# CONFIG_MBEDTLS_DYNAMIC_BUFFER is not set
+# CONFIG_MBEDTLS_DEBUG is not set
+
+#
+# mbedTLS v2.28.x related
+#
+# CONFIG_MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH is not set
+# CONFIG_MBEDTLS_X509_TRUSTED_CERT_CALLBACK is not set
+# CONFIG_MBEDTLS_SSL_CONTEXT_SERIALIZATION is not set
+CONFIG_MBEDTLS_SSL_KEEP_PEER_CERTIFICATE=y
+# end of mbedTLS v2.28.x related
+
+#
+# Certificate Bundle
+#
+CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=y
+CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL=y
+# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN is not set
+# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_NONE is not set
+# CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE is not set
+CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_MAX_CERTS=200
+# end of Certificate Bundle
+
+# CONFIG_MBEDTLS_ECP_RESTARTABLE is not set
+# CONFIG_MBEDTLS_CMAC_C is not set
+CONFIG_MBEDTLS_HARDWARE_AES=y
+CONFIG_MBEDTLS_AES_USE_INTERRUPT=y
+CONFIG_MBEDTLS_HARDWARE_GCM=y
+CONFIG_MBEDTLS_HARDWARE_MPI=y
+CONFIG_MBEDTLS_HARDWARE_SHA=y
+CONFIG_MBEDTLS_ROM_MD5=y
+# CONFIG_MBEDTLS_ATCA_HW_ECDSA_SIGN is not set
+# CONFIG_MBEDTLS_ATCA_HW_ECDSA_VERIFY is not set
+CONFIG_MBEDTLS_HAVE_TIME=y
+# CONFIG_MBEDTLS_HAVE_TIME_DATE is not set
+CONFIG_MBEDTLS_ECDSA_DETERMINISTIC=y
+CONFIG_MBEDTLS_SHA512_C=y
+CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT=y
+# CONFIG_MBEDTLS_TLS_SERVER_ONLY is not set
+# CONFIG_MBEDTLS_TLS_CLIENT_ONLY is not set
+# CONFIG_MBEDTLS_TLS_DISABLED is not set
+CONFIG_MBEDTLS_TLS_SERVER=y
+CONFIG_MBEDTLS_TLS_CLIENT=y
+CONFIG_MBEDTLS_TLS_ENABLED=y
+
+#
+# TLS Key Exchange Methods
+#
+# CONFIG_MBEDTLS_PSK_MODES is not set
+CONFIG_MBEDTLS_KEY_EXCHANGE_RSA=y
+CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA=y
+CONFIG_MBEDTLS_KEY_EXCHANGE_ELLIPTIC_CURVE=y
+CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA=y
+CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA=y
+CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA=y
+CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_RSA=y
+# end of TLS Key Exchange Methods
+
+CONFIG_MBEDTLS_SSL_RENEGOTIATION=y
+# CONFIG_MBEDTLS_SSL_PROTO_SSL3 is not set
+CONFIG_MBEDTLS_SSL_PROTO_TLS1=y
+CONFIG_MBEDTLS_SSL_PROTO_TLS1_1=y
+CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y
+# CONFIG_MBEDTLS_SSL_PROTO_GMTSSL1_1 is not set
+# CONFIG_MBEDTLS_SSL_PROTO_DTLS is not set
+CONFIG_MBEDTLS_SSL_ALPN=y
+CONFIG_MBEDTLS_CLIENT_SSL_SESSION_TICKETS=y
+CONFIG_MBEDTLS_X509_CHECK_KEY_USAGE=y
+CONFIG_MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE=y
+CONFIG_MBEDTLS_SERVER_SSL_SESSION_TICKETS=y
+
+#
+# Symmetric Ciphers
+#
+CONFIG_MBEDTLS_AES_C=y
+# CONFIG_MBEDTLS_CAMELLIA_C is not set
+# CONFIG_MBEDTLS_DES_C is not set
+CONFIG_MBEDTLS_RC4_DISABLED=y
+# CONFIG_MBEDTLS_RC4_ENABLED_NO_DEFAULT is not set
+# CONFIG_MBEDTLS_RC4_ENABLED is not set
+# CONFIG_MBEDTLS_BLOWFISH_C is not set
+# CONFIG_MBEDTLS_XTEA_C is not set
+CONFIG_MBEDTLS_CCM_C=y
+CONFIG_MBEDTLS_GCM_C=y
+# CONFIG_MBEDTLS_NIST_KW_C is not set
+# end of Symmetric Ciphers
+
+# CONFIG_MBEDTLS_RIPEMD160_C is not set
+
+#
+# Certificates
+#
+CONFIG_MBEDTLS_PEM_PARSE_C=y
+CONFIG_MBEDTLS_PEM_WRITE_C=y
+CONFIG_MBEDTLS_X509_CRL_PARSE_C=y
+CONFIG_MBEDTLS_X509_CSR_PARSE_C=y
+# end of Certificates
+
+CONFIG_MBEDTLS_ECP_C=y
+CONFIG_MBEDTLS_ECDH_C=y
+CONFIG_MBEDTLS_ECDSA_C=y
+# CONFIG_MBEDTLS_ECJPAKE_C is not set
+CONFIG_MBEDTLS_ECP_DP_SECP192R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP224R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP384R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP521R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP192K1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP224K1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP256K1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_BP256R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_BP384R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_BP512R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_CURVE25519_ENABLED=y
+CONFIG_MBEDTLS_ECP_NIST_OPTIM=y
+# CONFIG_MBEDTLS_POLY1305_C is not set
+# CONFIG_MBEDTLS_CHACHA20_C is not set
+# CONFIG_MBEDTLS_HKDF_C is not set
+# CONFIG_MBEDTLS_THREADING_C is not set
+# CONFIG_MBEDTLS_LARGE_KEY_SOFTWARE_MPI is not set
+# CONFIG_MBEDTLS_SECURITY_RISKS is not set
+# end of mbedTLS
+
+#
+# mDNS
+#
+CONFIG_MDNS_MAX_SERVICES=10
+CONFIG_MDNS_TASK_PRIORITY=1
+CONFIG_MDNS_TASK_STACK_SIZE=4096
+# CONFIG_MDNS_TASK_AFFINITY_NO_AFFINITY is not set
+CONFIG_MDNS_TASK_AFFINITY_CPU0=y
+CONFIG_MDNS_TASK_AFFINITY=0x0
+CONFIG_MDNS_SERVICE_ADD_TIMEOUT_MS=2000
+# CONFIG_MDNS_STRICT_MODE is not set
+CONFIG_MDNS_TIMER_PERIOD_MS=100
+# CONFIG_MDNS_NETWORKING_SOCKET is not set
+CONFIG_MDNS_MULTIPLE_INSTANCE=y
+# end of mDNS
+
+#
+# ESP-MQTT Configurations
+#
+CONFIG_MQTT_PROTOCOL_311=y
+CONFIG_MQTT_TRANSPORT_SSL=y
+CONFIG_MQTT_TRANSPORT_WEBSOCKET=y
+CONFIG_MQTT_TRANSPORT_WEBSOCKET_SECURE=y
+# CONFIG_MQTT_MSG_ID_INCREMENTAL is not set
+# CONFIG_MQTT_SKIP_PUBLISH_IF_DISCONNECTED is not set
+# CONFIG_MQTT_REPORT_DELETED_MESSAGES is not set
+# CONFIG_MQTT_USE_CUSTOM_CONFIG is not set
+# CONFIG_MQTT_TASK_CORE_SELECTION_ENABLED is not set
+# CONFIG_MQTT_CUSTOM_OUTBOX is not set
+# end of ESP-MQTT Configurations
+
+#
+# Newlib
+#
+CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF=y
+# CONFIG_NEWLIB_STDOUT_LINE_ENDING_LF is not set
+# CONFIG_NEWLIB_STDOUT_LINE_ENDING_CR is not set
+# CONFIG_NEWLIB_STDIN_LINE_ENDING_CRLF is not set
+# CONFIG_NEWLIB_STDIN_LINE_ENDING_LF is not set
+CONFIG_NEWLIB_STDIN_LINE_ENDING_CR=y
+# CONFIG_NEWLIB_NANO_FORMAT is not set
+# end of Newlib
+
+#
+# NVS
+#
+# CONFIG_NVS_ASSERT_ERROR_CHECK is not set
+# end of NVS
+
+#
+# OpenSSL
+#
+# CONFIG_OPENSSL_DEBUG is not set
+CONFIG_OPENSSL_ERROR_STACK=y
+# CONFIG_OPENSSL_ASSERT_DO_NOTHING is not set
+CONFIG_OPENSSL_ASSERT_EXIT=y
+# end of OpenSSL
+
+#
+# OpenThread
+#
+# CONFIG_OPENTHREAD_ENABLED is not set
+# end of OpenThread
+
+#
+# PThreads
+#
+CONFIG_PTHREAD_TASK_PRIO_DEFAULT=5
+CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072
+CONFIG_PTHREAD_STACK_MIN=768
+CONFIG_PTHREAD_TASK_CORE_DEFAULT=-1
+CONFIG_PTHREAD_TASK_NAME_DEFAULT="pthread"
+# end of PThreads
+
+#
+# SPI Flash driver
+#
+# CONFIG_SPI_FLASH_VERIFY_WRITE is not set
+# CONFIG_SPI_FLASH_ENABLE_COUNTERS is not set
+CONFIG_SPI_FLASH_ROM_DRIVER_PATCH=y
+CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS=y
+# CONFIG_SPI_FLASH_DANGEROUS_WRITE_FAILS is not set
+# CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED is not set
+# CONFIG_SPI_FLASH_USE_LEGACY_IMPL is not set
+# CONFIG_SPI_FLASH_BYPASS_BLOCK_ERASE is not set
+CONFIG_SPI_FLASH_YIELD_DURING_ERASE=y
+CONFIG_SPI_FLASH_ERASE_YIELD_DURATION_MS=20
+CONFIG_SPI_FLASH_ERASE_YIELD_TICKS=1
+CONFIG_SPI_FLASH_WRITE_CHUNK_SIZE=8192
+# CONFIG_SPI_FLASH_SIZE_OVERRIDE is not set
+# CONFIG_SPI_FLASH_CHECK_ERASE_TIMEOUT_DISABLED is not set
+# CONFIG_SPI_FLASH_OVERRIDE_CHIP_DRIVER_LIST is not set
+
+#
+# Auto-detect flash chips
+#
+CONFIG_SPI_FLASH_SUPPORT_ISSI_CHIP=y
+CONFIG_SPI_FLASH_SUPPORT_MXIC_CHIP=y
+CONFIG_SPI_FLASH_SUPPORT_GD_CHIP=y
+CONFIG_SPI_FLASH_SUPPORT_WINBOND_CHIP=y
+CONFIG_SPI_FLASH_SUPPORT_BOYA_CHIP=y
+CONFIG_SPI_FLASH_SUPPORT_TH_CHIP=y
+# end of Auto-detect flash chips
+
+CONFIG_SPI_FLASH_ENABLE_ENCRYPTED_READ_WRITE=y
+# end of SPI Flash driver
+
+#
+# SPIFFS Configuration
+#
+CONFIG_SPIFFS_MAX_PARTITIONS=3
+
+#
+# SPIFFS Cache Configuration
+#
+CONFIG_SPIFFS_CACHE=y
+CONFIG_SPIFFS_CACHE_WR=y
+# CONFIG_SPIFFS_CACHE_STATS is not set
+# end of SPIFFS Cache Configuration
+
+CONFIG_SPIFFS_PAGE_CHECK=y
+CONFIG_SPIFFS_GC_MAX_RUNS=10
+# CONFIG_SPIFFS_GC_STATS is not set
+CONFIG_SPIFFS_PAGE_SIZE=256
+CONFIG_SPIFFS_OBJ_NAME_LEN=32
+# CONFIG_SPIFFS_FOLLOW_SYMLINKS is not set
+CONFIG_SPIFFS_USE_MAGIC=y
+CONFIG_SPIFFS_USE_MAGIC_LENGTH=y
+CONFIG_SPIFFS_META_LENGTH=4
+CONFIG_SPIFFS_USE_MTIME=y
+
+#
+# Debug Configuration
+#
+# CONFIG_SPIFFS_DBG is not set
+# CONFIG_SPIFFS_API_DBG is not set
+# CONFIG_SPIFFS_GC_DBG is not set
+# CONFIG_SPIFFS_CACHE_DBG is not set
+# CONFIG_SPIFFS_CHECK_DBG is not set
+# CONFIG_SPIFFS_TEST_VISUALISATION is not set
+# end of Debug Configuration
+# end of SPIFFS Configuration
+
+#
+# TCP Transport
+#
+
+#
+# Websocket
+#
+CONFIG_WS_TRANSPORT=y
+CONFIG_WS_BUFFER_SIZE=1024
+# end of Websocket
+# end of TCP Transport
+
+#
+# TinyUSB Stack
+#
+# CONFIG_TINYUSB is not set
+# end of TinyUSB Stack
+
+#
+# Unity unit testing library
+#
+CONFIG_UNITY_ENABLE_FLOAT=y
+CONFIG_UNITY_ENABLE_DOUBLE=y
+# CONFIG_UNITY_ENABLE_64BIT is not set
+# CONFIG_UNITY_ENABLE_COLOR is not set
+CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
+# CONFIG_UNITY_ENABLE_FIXTURE is not set
+# CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL is not set
+# end of Unity unit testing library
+
+#
+# USB-OTG
+#
+CONFIG_USB_OTG_SUPPORTED=y
+CONFIG_USB_HOST_CONTROL_TRANSFER_MAX_SIZE=256
+CONFIG_USB_HOST_HW_BUFFER_BIAS_BALANCED=y
+# CONFIG_USB_HOST_HW_BUFFER_BIAS_IN is not set
+# CONFIG_USB_HOST_HW_BUFFER_BIAS_PERIODIC_OUT is not set
+# end of USB-OTG
+
+#
+# Virtual file system
+#
+CONFIG_VFS_SUPPORT_IO=y
+CONFIG_VFS_SUPPORT_DIR=y
+CONFIG_VFS_SUPPORT_SELECT=y
+CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT=y
+CONFIG_VFS_SUPPORT_TERMIOS=y
+
+#
+# Host File System I/O (Semihosting)
+#
+CONFIG_VFS_SEMIHOSTFS_MAX_MOUNT_POINTS=1
+# end of Host File System I/O (Semihosting)
+# end of Virtual file system
+
+#
+# Wear Levelling
+#
+# CONFIG_WL_SECTOR_SIZE_512 is not set
+CONFIG_WL_SECTOR_SIZE_4096=y
+CONFIG_WL_SECTOR_SIZE=4096
+# end of Wear Levelling
+
+#
+# Wi-Fi Provisioning Manager
+#
+CONFIG_WIFI_PROV_SCAN_MAX_ENTRIES=16
+CONFIG_WIFI_PROV_AUTOSTOP_TIMEOUT=30
+CONFIG_WIFI_PROV_BLE_FORCE_ENCRYPTION=y
+# end of Wi-Fi Provisioning Manager
+
+#
+# Supplicant
+#
+CONFIG_WPA_MBEDTLS_CRYPTO=y
+# CONFIG_WPA_WAPI_PSK is not set
+# CONFIG_WPA_SUITE_B_192 is not set
+# CONFIG_WPA_DEBUG_PRINT is not set
+# CONFIG_WPA_TESTING_OPTIONS is not set
+# CONFIG_WPA_WPS_STRICT is not set
+# CONFIG_WPA_11KV_SUPPORT is not set
+# CONFIG_WPA_MBO_SUPPORT is not set
+# CONFIG_WPA_DPP_SUPPORT is not set
+# end of Supplicant
+# end of Component config
+
+#
+# Compatibility options
+#
+# CONFIG_LEGACY_INCLUDE_COMMON_HEADERS is not set
+# end of Compatibility options
+
+# Deprecated options for backward compatibility
+CONFIG_TOOLPREFIX="xtensa-esp32s2-elf-"
+# CONFIG_LOG_BOOTLOADER_LEVEL_NONE is not set
+# CONFIG_LOG_BOOTLOADER_LEVEL_ERROR is not set
+# CONFIG_LOG_BOOTLOADER_LEVEL_WARN is not set
+CONFIG_LOG_BOOTLOADER_LEVEL_INFO=y
+# CONFIG_LOG_BOOTLOADER_LEVEL_DEBUG is not set
+# CONFIG_LOG_BOOTLOADER_LEVEL_VERBOSE is not set
+CONFIG_LOG_BOOTLOADER_LEVEL=3
+# CONFIG_APP_ROLLBACK_ENABLE is not set
+# CONFIG_FLASH_ENCRYPTION_ENABLED is not set
+# CONFIG_FLASHMODE_QIO is not set
+# CONFIG_FLASHMODE_QOUT is not set
+CONFIG_FLASHMODE_DIO=y
+# CONFIG_FLASHMODE_DOUT is not set
+# CONFIG_MONITOR_BAUD_9600B is not set
+# CONFIG_MONITOR_BAUD_57600B is not set
+CONFIG_MONITOR_BAUD_115200B=y
+# CONFIG_MONITOR_BAUD_230400B is not set
+# CONFIG_MONITOR_BAUD_921600B is not set
+# CONFIG_MONITOR_BAUD_2MB is not set
+# CONFIG_MONITOR_BAUD_OTHER is not set
+CONFIG_MONITOR_BAUD_OTHER_VAL=115200
+CONFIG_MONITOR_BAUD=115200
+CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG=y
+# CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE is not set
+CONFIG_OPTIMIZATION_ASSERTIONS_ENABLED=y
+# CONFIG_OPTIMIZATION_ASSERTIONS_SILENT is not set
+# CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED is not set
+CONFIG_OPTIMIZATION_ASSERTION_LEVEL=2
+# CONFIG_CXX_EXCEPTIONS is not set
+CONFIG_STACK_CHECK_NONE=y
+# CONFIG_STACK_CHECK_NORM is not set
+# CONFIG_STACK_CHECK_STRONG is not set
+# CONFIG_STACK_CHECK_ALL is not set
+# CONFIG_WARN_WRITE_STRINGS is not set
+# CONFIG_DISABLE_GCC8_WARNINGS is not set
+# CONFIG_ESP32_APPTRACE_DEST_TRAX is not set
+CONFIG_ESP32_APPTRACE_DEST_NONE=y
+CONFIG_ESP32_APPTRACE_LOCK_ENABLE=y
+CONFIG_ADC2_DISABLE_DAC=y
+# CONFIG_EVENT_LOOP_PROFILING is not set
+CONFIG_POST_EVENTS_FROM_ISR=y
+CONFIG_POST_EVENTS_FROM_IRAM_ISR=y
+CONFIG_ESP_SYSTEM_PD_FLASH=y
+# CONFIG_ESP32C3_LIGHTSLEEP_GPIO_RESET_WORKAROUND is not set
+CONFIG_IPC_TASK_STACK_SIZE=1536
+CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE=y
+# CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION is not set
+CONFIG_ESP32_PHY_MAX_WIFI_TX_POWER=20
+CONFIG_ESP32_PHY_MAX_TX_POWER=20
+# CONFIG_ESP32S2_PANIC_PRINT_HALT is not set
+CONFIG_ESP32S2_PANIC_PRINT_REBOOT=y
+# CONFIG_ESP32S2_PANIC_SILENT_REBOOT is not set
+# CONFIG_ESP32S2_PANIC_GDBSTUB is not set
+CONFIG_ESP32S2_ALLOW_RTC_FAST_MEM_AS_HEAP=y
+CONFIG_ESP32H2_MEMPROT_FEATURE=y
+CONFIG_ESP32H2_MEMPROT_FEATURE_LOCK=y
+CONFIG_SYSTEM_EVENT_QUEUE_SIZE=32
+CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=2304
+CONFIG_MAIN_TASK_STACK_SIZE=3584
+CONFIG_CONSOLE_UART_DEFAULT=y
+# CONFIG_CONSOLE_UART_CUSTOM is not set
+# CONFIG_ESP_CONSOLE_UART_NONE is not set
+CONFIG_CONSOLE_UART=y
+CONFIG_CONSOLE_UART_NUM=0
+CONFIG_CONSOLE_UART_BAUDRATE=115200
+CONFIG_INT_WDT=y
+CONFIG_INT_WDT_TIMEOUT_MS=300
+CONFIG_TASK_WDT=y
+# CONFIG_TASK_WDT_PANIC is not set
+CONFIG_TASK_WDT_TIMEOUT_S=5
+CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0=y
+# CONFIG_ESP32_DEBUG_STUBS_ENABLE is not set
+CONFIG_TIMER_TASK_STACK_SIZE=3584
+# CONFIG_EXTERNAL_COEX_ENABLE is not set
+# CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH is not set
+# CONFIG_ESP32_ENABLE_COREDUMP_TO_UART is not set
+CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE=y
+CONFIG_MB_MASTER_TIMEOUT_MS_RESPOND=150
+CONFIG_MB_MASTER_DELAY_MS_CONVERT=200
+CONFIG_MB_QUEUE_LENGTH=20
+CONFIG_MB_SERIAL_TASK_STACK_SIZE=4096
+CONFIG_MB_SERIAL_BUF_SIZE=256
+CONFIG_MB_SERIAL_TASK_PRIO=10
+CONFIG_MB_CONTROLLER_SLAVE_ID_SUPPORT=y
+CONFIG_MB_CONTROLLER_SLAVE_ID=0x00112233
+CONFIG_MB_CONTROLLER_NOTIFY_TIMEOUT=20
+CONFIG_MB_CONTROLLER_NOTIFY_QUEUE_SIZE=20
+CONFIG_MB_CONTROLLER_STACK_SIZE=4096
+CONFIG_MB_EVENT_QUEUE_TIMEOUT=20
+# CONFIG_MB_TIMER_PORT_ENABLED is not set
+CONFIG_MB_TIMER_GROUP=0
+CONFIG_MB_TIMER_INDEX=0
+# CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK is not set
+CONFIG_TIMER_TASK_PRIORITY=1
+CONFIG_TIMER_TASK_STACK_DEPTH=2048
+CONFIG_TIMER_QUEUE_LENGTH=10
+# CONFIG_L2_TO_L3_COPY is not set
+# CONFIG_USE_ONLY_LWIP_SELECT is not set
+CONFIG_ESP_GRATUITOUS_ARP=y
+CONFIG_GARP_TMR_INTERVAL=60
+CONFIG_TCPIP_RECVMBOX_SIZE=32
+CONFIG_TCP_MAXRTX=12
+CONFIG_TCP_SYNMAXRTX=12
+CONFIG_TCP_MSS=1440
+CONFIG_TCP_MSL=60000
+CONFIG_TCP_SND_BUF_DEFAULT=5744
+CONFIG_TCP_WND_DEFAULT=5744
+CONFIG_TCP_RECVMBOX_SIZE=6
+CONFIG_TCP_QUEUE_OOSEQ=y
+# CONFIG_ESP_TCP_KEEP_CONNECTION_WHEN_IP_CHANGES is not set
+CONFIG_TCP_OVERSIZE_MSS=y
+# CONFIG_TCP_OVERSIZE_QUARTER_MSS is not set
+# CONFIG_TCP_OVERSIZE_DISABLE is not set
+CONFIG_UDP_RECVMBOX_SIZE=6
+CONFIG_TCPIP_TASK_STACK_SIZE=3072
+CONFIG_TCPIP_TASK_AFFINITY_NO_AFFINITY=y
+# CONFIG_TCPIP_TASK_AFFINITY_CPU0 is not set
+CONFIG_TCPIP_TASK_AFFINITY=0x7FFFFFFF
+# CONFIG_PPP_SUPPORT is not set
+CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT=5
+CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072
+CONFIG_ESP32_PTHREAD_STACK_MIN=768
+CONFIG_ESP32_PTHREAD_TASK_CORE_DEFAULT=-1
+CONFIG_ESP32_PTHREAD_TASK_NAME_DEFAULT="pthread"
+CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS=y
+# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_FAILS is not set
+# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ALLOWED is not set
+# CONFIG_USB_ENABLED is not set
+CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT=y
+CONFIG_SUPPORT_TERMIOS=y
+CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS=1
+# End of deprecated options