✅ 添加(ESP32-S2 code):添加ESP32S2的代码,并且初步点亮屏幕
This commit is contained in:
parent
8a2dafc1bd
commit
abeacdcdb0
43
main/APP/app_task_hello/app_task_hello.c
Normal file
43
main/APP/app_task_hello/app_task_hello.c
Normal file
@ -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 修改日志:
|
||||
* <table>
|
||||
* <tr><th>Date <th>Version <th>Author <th>Description
|
||||
* <tr><td>2022-09-28 <td>v1.0 <td>impressionyang <td>内容
|
||||
* </table>
|
||||
*/
|
||||
#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;
|
||||
}
|
||||
52
main/APP/app_task_hello/app_task_hello.h
Normal file
52
main/APP/app_task_hello/app_task_hello.h
Normal file
@ -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 修改日志:
|
||||
* <table>
|
||||
* <tr><th>Date <th>Version <th>Author <th>Description
|
||||
* <tr><td>2022-09-28 <td>v1.0 <td>impressionyang <td>内容
|
||||
* </table>
|
||||
*/
|
||||
#ifndef __APP_HELLO_TASK_H__
|
||||
#define __APP_HELLO_TASK_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#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__
|
||||
177
main/APP/app_task_mqtt/app_task_mqtt.c
Normal file
177
main/APP/app_task_mqtt/app_task_mqtt.c
Normal file
@ -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 修改日志:
|
||||
* <table>
|
||||
* <tr><th>Date <th>Version <th>Author <th>Description
|
||||
* <tr><td>2022-09-29 <td>v1.0 <td>impressionyang <td>内容
|
||||
* </table>
|
||||
*/
|
||||
#include "app_task_mqtt.h"
|
||||
#include "app_main.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#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;
|
||||
}
|
||||
52
main/APP/app_task_mqtt/app_task_mqtt.h
Normal file
52
main/APP/app_task_mqtt/app_task_mqtt.h
Normal file
@ -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 修改日志:
|
||||
* <table>
|
||||
* <tr><th>Date <th>Version <th>Author <th>Description
|
||||
* <tr><td>2022-09-29 <td>v1.0 <td>impressionyang <td>内容
|
||||
* </table>
|
||||
*/
|
||||
#ifndef __APP_TASK_MQTT_H__
|
||||
#define __APP_TASK_MQTT_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#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__
|
||||
152
main/APP/app_task_sensors/app_task_sensors.c
Normal file
152
main/APP/app_task_sensors/app_task_sensors.c
Normal file
@ -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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#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);
|
||||
|
||||
|
||||
17
main/APP/app_task_sensors/app_task_sensors.h
Normal file
17
main/APP/app_task_sensors/app_task_sensors.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef __APP_TASK_SENSORS_H__
|
||||
#define __APP_TASK_SENSORS_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#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__
|
||||
148
main/APP/app_task_wifi/app_task_wifi.c
Normal file
148
main/APP/app_task_wifi/app_task_wifi.c
Normal file
@ -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 修改日志:
|
||||
* <table>
|
||||
* <tr><th>Date <th>Version <th>Author <th>Description
|
||||
* <tr><td>2022-09-29 <td>v1.0 <td>impressionyang <td>内容
|
||||
* </table>
|
||||
*/
|
||||
#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 <string.h>
|
||||
|
||||
/* 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;
|
||||
}
|
||||
74
main/APP/app_task_wifi/app_task_wifi.h
Normal file
74
main/APP/app_task_wifi/app_task_wifi.h
Normal file
@ -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 修改日志:
|
||||
* <table>
|
||||
* <tr><th>Date <th>Version <th>Author <th>Description
|
||||
* <tr><td>2022-09-29 <td>v1.0 <td>impressionyang <td>内容
|
||||
* </table>
|
||||
*/
|
||||
#ifndef __APP_TASK_WIFI_H__
|
||||
#define __APP_TASK_WIFI_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#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__
|
||||
@ -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"
|
||||
)
|
||||
|
||||
139
main/Kconfig.projbuild
Normal file
139
main/Kconfig.projbuild
Normal file
@ -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
|
||||
192
main/app_main.c
Normal file
192
main/app_main.c
Normal file
@ -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 <stdio.h>
|
||||
#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);
|
||||
|
||||
48
main/app_main.h
Normal file
48
main/app_main.h
Normal file
@ -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 修改日志:
|
||||
* <table>
|
||||
* <tr><th>Date <th>Version <th>Author <th>Description
|
||||
* <tr><td>2022-09-29 <td>v1.0 <td>impressionyang <td>内容
|
||||
* </table>
|
||||
*/
|
||||
#ifndef __APP_MAIN_H__
|
||||
#define __APP_MAIN_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#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__
|
||||
113
main/drivers/cst816/CST816T.c
Normal file
113
main/drivers/cst816/CST816T.c
Normal file
@ -0,0 +1,113 @@
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#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;
|
||||
}
|
||||
50
main/drivers/cst816/CST816T.h
Normal file
50
main/drivers/cst816/CST816T.h
Normal file
@ -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
|
||||
1032
main/drivers/drv_bmp280_3v3/bmp2/bmp2.c
Normal file
1032
main/drivers/drv_bmp280_3v3/bmp2/bmp2.c
Normal file
File diff suppressed because it is too large
Load Diff
393
main/drivers/drv_bmp280_3v3/bmp2/bmp2.h
Normal file
393
main/drivers/drv_bmp280_3v3/bmp2/bmp2.h
Normal file
@ -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 */
|
||||
602
main/drivers/drv_bmp280_3v3/bmp2/bmp2_defs.h
Normal file
602
main/drivers/drv_bmp280_3v3/bmp2/bmp2_defs.h
Normal file
@ -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 <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#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 */
|
||||
170
main/drivers/drv_bmp280_3v3/drv_bmp280_3v3.c
Normal file
170
main/drivers/drv_bmp280_3v3/drv_bmp280_3v3.c
Normal file
@ -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 修改日志:
|
||||
* <table>
|
||||
* <tr><th>Date <th>Version <th>Author <th>Description
|
||||
* <tr><td>2022-10-09 <td>v1.0 <td>impressionyang <td>内容
|
||||
* </table>
|
||||
*/
|
||||
#include "drv_bmp280_3v3.h"
|
||||
#include <stdio.h>
|
||||
#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;
|
||||
}
|
||||
51
main/drivers/drv_bmp280_3v3/drv_bmp280_3v3.h
Normal file
51
main/drivers/drv_bmp280_3v3/drv_bmp280_3v3.h
Normal file
@ -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 修改日志:
|
||||
* <table>
|
||||
* <tr><th>Date <th>Version <th>Author <th>Description
|
||||
* <tr><td>2022-10-09 <td>v1.0 <td>impressionyang <td>内容
|
||||
* </table>
|
||||
*/
|
||||
#ifndef __DRV_BMP280_3V3_H__
|
||||
#define __DRV_BMP280_3V3_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#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__
|
||||
211
main/drivers/msg_queue/msg_queue.c
Normal file
211
main/drivers/msg_queue/msg_queue.c
Normal file
@ -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 修改日志:
|
||||
* <table>
|
||||
* <tr><th>Date <th>Version <th>Author <th>Description
|
||||
* <tr><td>2022-10-09 <td>v1.0 <td>impressionyang <td>内容
|
||||
* </table>
|
||||
*/
|
||||
#include "msg_queue.h"
|
||||
#include "link_list.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
112
main/drivers/msg_queue/msg_queue.h
Normal file
112
main/drivers/msg_queue/msg_queue.h
Normal file
@ -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 修改日志:
|
||||
* <table>
|
||||
* <tr><th>Date <th>Version <th>Author <th>Description
|
||||
* <tr><td>2022-10-09 <td>v1.0 <td>impressionyang <td>内容
|
||||
* </table>
|
||||
*/
|
||||
#ifndef __MSG_QUEUE_H__
|
||||
#define __MSG_QUEUE_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#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__
|
||||
51
main/drivers/st7789/bmpfile.h
Normal file
51
main/drivers/st7789/bmpfile.h
Normal file
@ -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 2<sup><i>n</i></sup>. */
|
||||
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__ */
|
||||
186
main/drivers/st7789/decode_jpeg.c
Normal file
186
main/drivers/st7789/decode_jpeg.c
Normal file
@ -0,0 +1,186 @@
|
||||
#include <stdio.h>
|
||||
#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;
|
||||
}
|
||||
|
||||
34
main/drivers/st7789/decode_jpeg.h
Normal file
34
main/drivers/st7789/decode_jpeg.h
Normal file
@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#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);
|
||||
|
||||
61
main/drivers/st7789/decode_png.c
Normal file
61
main/drivers/st7789/decode_png.c
Normal file
@ -0,0 +1,61 @@
|
||||
#include <stdio.h>
|
||||
#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");
|
||||
}
|
||||
9
main/drivers/st7789/decode_png.h
Normal file
9
main/drivers/st7789/decode_png.h
Normal file
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#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);
|
||||
|
||||
582
main/drivers/st7789/fontx.c
Normal file
582
main/drivers/st7789/fontx.c
Normal file
@ -0,0 +1,582 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#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;i<sizeof(buf);i++) {
|
||||
printf("buf[%d]=0x%x\n",i,buf[i]);
|
||||
}
|
||||
}
|
||||
memcpy(fx->fxname, &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<w; x++){
|
||||
line[y*32+x] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int mask = 7;
|
||||
int fontp;
|
||||
fontp = 0;
|
||||
for(y=0; y<h; y++){
|
||||
for(x=0; x<w; x++){
|
||||
uint8_t d = fonts[fontp+x/8];
|
||||
uint8_t linep = (y/8)*32+x;
|
||||
if (d & (0x80 >> (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<w; x++){
|
||||
line[y*32+x] = RotateByte(line[y*32+x]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// アンダーラインを追加
|
||||
void UnderlineBitmap(uint8_t *line, uint8_t w, uint8_t h) {
|
||||
int x,y;
|
||||
uint8_t wk;
|
||||
for(y=0; y<(h/8); y++){
|
||||
for(x=0; x<w; x++){
|
||||
wk = line[y*32+x];
|
||||
if ( (y+1) == (h/8)) line[y*32+x] = wk + 0x80;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ビットマップを反転
|
||||
void ReversBitmap(uint8_t *line, uint8_t w, uint8_t h) {
|
||||
int x,y;
|
||||
uint8_t wk;
|
||||
for(y=0; y<(h/8); y++){
|
||||
for(x=0; x<w; x++){
|
||||
wk = line[y*32+x];
|
||||
line[y*32+x] = ~wk;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// フォントパターンの表示
|
||||
void ShowFont(uint8_t *fonts, uint8_t pw, uint8_t ph) {
|
||||
int x,y,fpos;
|
||||
printf("[ShowFont pw=%d ph=%d]\n",pw,ph);
|
||||
fpos=0;
|
||||
for (y=0;y<ph;y++) {
|
||||
printf("%02d",y);
|
||||
for (x=0;x<pw;x++) {
|
||||
if (fonts[fpos+x/8] & (0x80 >> (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<pw;x++) {
|
||||
printf("%02x ",bitmap[x+y*32]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
fpos=0;
|
||||
for (y=0;y<ph;y++) {
|
||||
printf("%02d",y);
|
||||
for (x=0;x<pw;x++) {
|
||||
//printf("b=%x m=%x\n",bitmap[x+(y/8)*32],0x80 >> 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<stlen;i++) {
|
||||
sp = str_in[i];
|
||||
if(FontxDebug)printf("[String2SJIS]sp[%d]=%x\n",i,sp);
|
||||
if ((sp & 0xf0) == 0xe0) { // 上位4ビットが1110なら、3バイト文字の1バイト目
|
||||
c1 = sp;
|
||||
} else if ((sp & 0xc0) == 0x80) { // 上位2ビットが10なら、他バイト文字の2バイト目以降
|
||||
if (c2 == 0) {
|
||||
c2 = sp;
|
||||
} else {
|
||||
if (c1 == 0xef && c2 == 0xbd) {
|
||||
if(FontxDebug)printf("[String2SJIS]hankaku kana %x-%x-%x\n",c1,c2,sp);
|
||||
sjis2 = sp;
|
||||
if(FontxDebug)printf("[String2SJIS]sjis2=%x\n",sjis2);
|
||||
if (spos < ssize) sjis[spos++] = sjis2;
|
||||
} else if (c1 == 0xef && c2 == 0xbe) {
|
||||
if(FontxDebug)printf("[String2SJIS]hankaku kana %x-%x-%x\n",c1,c2,sp);
|
||||
sjis2 = 0xc0 + (sp - 0x80);
|
||||
if(FontxDebug)printf("[String2SJIS]sjis2=%x\n",sjis2);
|
||||
if (spos < ssize) sjis[spos++] = sjis2;
|
||||
} else {
|
||||
if(FontxDebug)printf("[String2SJIS]UTF8 %x-%x-%x\n",c1,c2,sp);
|
||||
utf8[0] = c1;
|
||||
utf8[1] = c2;
|
||||
utf8[2] = sp;
|
||||
sjis2 = UTF2SJIS(fd, utf8);
|
||||
if(FontxDebug)printf("[String2SJIS]sjis2=%x\n",sjis2);
|
||||
if (spos < ssize) sjis[spos++] = sjis2;
|
||||
}
|
||||
c1 = c2 = 0;
|
||||
}
|
||||
} else if ((sp & 0x80) == 0) { // 1バイト文字の場合
|
||||
if(FontxDebug)printf("[String2SJIS]ANK %x\n",sp);
|
||||
if (spos < ssize) sjis[spos++] = sp;
|
||||
}
|
||||
}
|
||||
return spos;
|
||||
}
|
||||
#endif
|
||||
|
||||
39
main/drivers/st7789/fontx.h
Normal file
39
main/drivers/st7789/fontx.h
Normal file
@ -0,0 +1,39 @@
|
||||
#ifndef MAIN_FONTX_H_
|
||||
#define MAIN_FONTX_H_
|
||||
#define FontxGlyphBufSize (32*32/8)
|
||||
|
||||
typedef struct {
|
||||
const char *path;
|
||||
char fxname[10];
|
||||
bool opened;
|
||||
bool valid;
|
||||
bool is_ank;
|
||||
uint8_t w;
|
||||
uint8_t h;
|
||||
uint16_t fsz;
|
||||
uint8_t bc;
|
||||
FILE *file;
|
||||
} FontxFile;
|
||||
|
||||
void AaddFontx(FontxFile *fx, const char *path);
|
||||
void InitFontx(FontxFile *fxs, const char *f0, const char *f1);
|
||||
bool OpenFontx(FontxFile *fx);
|
||||
void CloseFontx(FontxFile *fx);
|
||||
void DumpFontx(FontxFile *fxs);
|
||||
uint8_t getFortWidth(FontxFile *fx);
|
||||
uint8_t getFortHeight(FontxFile *fx);
|
||||
bool GetFontx(FontxFile *fxs, uint8_t ascii , uint8_t *pGlyph, uint8_t *pw, uint8_t *ph);
|
||||
void Font2Bitmap(uint8_t *fonts, uint8_t *line, uint8_t w, uint8_t h, uint8_t inverse);
|
||||
void UnderlineBitmap(uint8_t *line, uint8_t w, uint8_t h);
|
||||
void ReversBitmap(uint8_t *line, uint8_t w, uint8_t h);
|
||||
void ShowFont(uint8_t *fonts, uint8_t pw, uint8_t ph);
|
||||
void ShowBitmap(uint8_t *bitmap, uint8_t pw, uint8_t ph);
|
||||
uint8_t RotateByte(uint8_t ch);
|
||||
|
||||
// UTF8 to SJIS table
|
||||
// https://www.mgo-tec.com/blog-entry-utf8sjis01.html
|
||||
//#define Utf8Sjis "Utf8Sjis.tbl"
|
||||
//uint16_t UTF2SJIS(spiffs_file fd, uint8_t *utf8);
|
||||
//int String2SJIS(spiffs_file fd, unsigned char *str_in, size_t stlen, uint16_t *sjis, size_t ssize);
|
||||
#endif /* MAIN_FONTX_H_ */
|
||||
|
||||
830
main/drivers/st7789/pngle.c
Normal file
830
main/drivers/st7789/pngle.c
Normal file
@ -0,0 +1,830 @@
|
||||
/*-
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <math.h>
|
||||
|
||||
#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: */
|
||||
189
main/drivers/st7789/pngle.h
Normal file
189
main/drivers/st7789/pngle.h
Normal file
@ -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 <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#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__ */
|
||||
1111
main/drivers/st7789/st7789.c
Normal file
1111
main/drivers/st7789/st7789.c
Normal file
File diff suppressed because it is too large
Load Diff
81
main/drivers/st7789/st7789.h
Normal file
81
main/drivers/st7789/st7789.h
Normal file
@ -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_ */
|
||||
|
||||
8
main/utilities/letter_shell/port/esp-idf/CMakeLists.txt
Normal file
8
main/utilities/letter_shell/port/esp-idf/CMakeLists.txt
Normal file
@ -0,0 +1,8 @@
|
||||
idf_component_register(
|
||||
SRCS "src/shell.c"
|
||||
"src/shell_ext.c"
|
||||
"shell_port.c"
|
||||
INCLUDE_DIRS "./"
|
||||
"./src"
|
||||
LDFRAGMENTS "shell.lf"
|
||||
)
|
||||
13
main/utilities/letter_shell/port/esp-idf/readme.md
Normal file
13
main/utilities/letter_shell/port/esp-idf/readme.md
Normal file
@ -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` 文件
|
||||
13
main/utilities/letter_shell/port/esp-idf/shell.lf
Normal file
13
main/utilities/letter_shell/port/esp-idf/shell.lf
Normal file
@ -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)
|
||||
190
main/utilities/letter_shell/port/esp-idf/shell_cfg.h
Normal file
190
main/utilities/letter_shell/port/esp-idf/shell_cfg.h
Normal file
@ -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
|
||||
70
main/utilities/letter_shell/port/esp-idf/shell_port.c
Normal file
70
main/utilities/letter_shell/port/esp-idf/shell_port.c
Normal file
@ -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);
|
||||
}
|
||||
20
main/utilities/letter_shell/port/esp-idf/shell_port.h
Normal file
20
main/utilities/letter_shell/port/esp-idf/shell_port.h
Normal file
@ -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
|
||||
2011
main/utilities/letter_shell/src/shell.c
Normal file
2011
main/utilities/letter_shell/src/shell.c
Normal file
File diff suppressed because it is too large
Load Diff
472
main/utilities/letter_shell/src/shell.h
Normal file
472
main/utilities/letter_shell/src/shell.h
Normal file
@ -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
|
||||
|
||||
|
||||
188
main/utilities/letter_shell/src/shell_cfg.h
Normal file
188
main/utilities/letter_shell/src/shell_cfg.h
Normal file
@ -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
|
||||
103
main/utilities/letter_shell/src/shell_cmd_list.c
Normal file
103
main/utilities/letter_shell/src/shell_cmd_list.c
Normal file
@ -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
|
||||
87
main/utilities/letter_shell/src/shell_companion.c
Normal file
87
main/utilities/letter_shell/src/shell_companion.c
Normal file
@ -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 */
|
||||
447
main/utilities/letter_shell/src/shell_ext.c
Normal file
447
main/utilities/letter_shell/src/shell_ext.c
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
33
main/utilities/letter_shell/src/shell_ext.h
Normal file
33
main/utilities/letter_shell/src/shell_ext.h
Normal file
@ -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
|
||||
144
main/utilities/link_list/link_list.c
Normal file
144
main/utilities/link_list/link_list.c
Normal file
@ -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 修改日志:
|
||||
* <table>
|
||||
* <tr><th>Date <th>Version <th>Author <th>Description
|
||||
* <tr><td>2022-10-12 <td>v1.0 <td>impressionyang <td>内容
|
||||
* </table>
|
||||
*/
|
||||
#include "link_list.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
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;
|
||||
}
|
||||
128
main/utilities/link_list/link_list.h
Normal file
128
main/utilities/link_list/link_list.h
Normal file
@ -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 修改日志:
|
||||
* <table>
|
||||
* <tr><th>Date <th>Version <th>Author <th>Description
|
||||
* <tr><td>2022-10-12 <td>v1.0 <td>impressionyang <td>内容
|
||||
* </table>
|
||||
*/
|
||||
#ifndef __LINK_LIST_H__
|
||||
#define __LINK_LIST_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#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__
|
||||
1376
sdkconfig.old
Normal file
1376
sdkconfig.old
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user