添加(ESP32-S2 code):添加ESP32S2的代码,并且初步点亮屏幕

This commit is contained in:
Alvin Young 2022-10-23 17:06:54 +08:00
parent 8a2dafc1bd
commit abeacdcdb0
49 changed files with 13716 additions and 2 deletions

View 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;
}

View 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__

View 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;
}

View 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__

View 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) , &reg_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);

View 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__

View 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;
}

View 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__

View File

@ -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
View 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
View 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
View 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__

View 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;
}

View 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

File diff suppressed because it is too large Load Diff

View 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 */

View 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 */

View 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;
}

View 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__

View 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;
}

View 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__

View 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__ */

View 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;
}

View 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);

View 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");
}

View 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
View 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

View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

View 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_ */

View 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"
)

View 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` 文件

View 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)

View 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

View 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);
}

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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

View 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

View 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 */

View 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;
}
}

View 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

View 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;
}

View 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 Normal file

File diff suppressed because it is too large Load Diff

1376
sdkconfig.old Normal file

File diff suppressed because it is too large Load Diff