参考代码
This commit is contained in:
8
CMakeLists.txt
Normal file
8
CMakeLists.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
# For more information about build system see
|
||||
# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html
|
||||
# The following five lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(project)
|
||||
79
app/app_main.c
Normal file
79
app/app_main.c
Normal file
@@ -0,0 +1,79 @@
|
||||
#include "app_main.h"
|
||||
|
||||
/* 标准库 */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* 配置 */
|
||||
#include "config/board_config.h"
|
||||
|
||||
/* SDK */
|
||||
#include "esp_err.h"
|
||||
|
||||
/* 通用模块 */
|
||||
#include "button/button_event.h"
|
||||
|
||||
/* 应用模块 */
|
||||
|
||||
/* 自定义框架抽象层 */
|
||||
#include "os/os.h"
|
||||
#include "os/os_common.h"
|
||||
#include "console.h"
|
||||
#include "shell/sh_vset.h"
|
||||
|
||||
#define CONFIG_SYS_LOG_LEVEL SYS_LOG_LEVEL_DBG
|
||||
#define SYS_LOG_DOMAIN "MAIN"
|
||||
#include "sys_log.h"
|
||||
|
||||
nvs_handle g_nvs_hdl; // nvs 句柄
|
||||
os_work_q_t g_work_q_hdl_low; // 低于 default_os_work_q_hdl 优先级的工作队列
|
||||
|
||||
static void _init_nvs(void);
|
||||
static int _change_mode_event_button(const button_event_t *event);
|
||||
static void _vset_cb(sh_t *sh_hdl);
|
||||
|
||||
void work_app_main(void *arg)
|
||||
{
|
||||
/* 初始化 SDK 的 nvs 模块 */
|
||||
_init_nvs();
|
||||
|
||||
/* 初始化按键检测和控制 */
|
||||
button_init(PIN_BIT(g_cfg_board->key_boot.pin), g_cfg_board->key_boot.en_lev);
|
||||
|
||||
button_event_add_callback(g_cfg_board->key_boot.pin, _change_mode_event_button);
|
||||
|
||||
/* 启动 shell */
|
||||
SYS_LOG_INF("app start");
|
||||
vset_init(&g_uart_handle_vt100, _vset_cb);
|
||||
os_thread_sleep(100);
|
||||
shell_start();
|
||||
}
|
||||
|
||||
static void _init_nvs(void)
|
||||
{
|
||||
#define _NVS_NAME "nvs-app"
|
||||
if (g_nvs_hdl == 0)
|
||||
{
|
||||
ESP_ERROR_CHECK(nvs_open(_NVS_NAME, NVS_READWRITE, &g_nvs_hdl));
|
||||
}
|
||||
}
|
||||
|
||||
static int _change_mode_event_button(const button_event_t *event)
|
||||
{
|
||||
static const char *const stat_tab[] = {
|
||||
[BUTTON_UP] = "up",
|
||||
[BUTTON_DOWN] = "down",
|
||||
[BUTTON_HELD] = "held",
|
||||
};
|
||||
if (event->event < __ARRAY_SIZE(stat_tab))
|
||||
{
|
||||
SYS_LOG_DBG("button stat: %s", stat_tab[event->event]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _vset_cb(sh_t *sh_hdl)
|
||||
{
|
||||
}
|
||||
7
app/app_main.h
Normal file
7
app/app_main.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "nvs.h"
|
||||
#include "os/os.h"
|
||||
|
||||
extern nvs_handle g_nvs_hdl; // nvs 句柄
|
||||
extern os_work_q_t g_work_q_hdl_low; // 低于 default_os_work_q_hdl 优先级的工作队列
|
||||
395
app/button/button_event.c
Normal file
395
app/button/button_event.c
Normal file
@@ -0,0 +1,395 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "driver/gpio.h"
|
||||
|
||||
#include "os/os.h"
|
||||
|
||||
#include "button_event.h"
|
||||
|
||||
#define CONFIG_SYS_LOG_LEVEL SYS_LOG_LEVEL_WRN
|
||||
#define SYS_LOG_DOMAIN "BUTTON"
|
||||
#include "sys_log.h"
|
||||
|
||||
#define VOLTAGE_HIGH 1 // 高电平有效
|
||||
#define VOLTAGE_LOW 0 // 高电平有效
|
||||
|
||||
#define DEBOUNCE_CHECK_VOLTAGE_CHANGED 1
|
||||
#define DEBOUNCE_CHECK_VOLTAGE_DID_NOT_CHANGED 0
|
||||
|
||||
#define DEBOUCE_CHECK_MAX_TIMES 5
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t pin;
|
||||
uint8_t is_inverted; // 是否反向,如果为真的话,则当按钮按下后,引脚为低电平
|
||||
uint16_t history;
|
||||
uint32_t down_time;
|
||||
uint32_t next_long_time;
|
||||
int current_voltage; // 当前引脚电平
|
||||
int debounce_check_counter;
|
||||
uint8_t allow_multiple_long_press_event;
|
||||
uint8_t long_press_event_sent;
|
||||
} debounce_t;
|
||||
|
||||
int pin_count = -1;
|
||||
debounce_t *debounce;
|
||||
static os_queue_t s_event_queue; // 当出现按键变化时被传送到的队列对象
|
||||
static button_callback_t *g_callback_list_head = NULL;
|
||||
static button_callback_t *g_callback_list_tail = NULL;
|
||||
static os_work_t s_work_hdl;
|
||||
|
||||
static os_queue_t *_pulled_button_init(unsigned long long pin_select, gpio_pull_mode_t pull_mode);
|
||||
|
||||
static uint32_t millis()
|
||||
{
|
||||
return os_get_sys_time();
|
||||
}
|
||||
|
||||
static int send_event(debounce_t *db, button_event_e ev)
|
||||
{
|
||||
static char *const ev_tbl[] = {
|
||||
[BUTTON_UP] = "release",
|
||||
[BUTTON_DOWN] = "press",
|
||||
[BUTTON_HELD] = "held"};
|
||||
SYS_ASSERT(ev < sizeof(ev_tbl), "ev: %d", ev);
|
||||
SYS_LOG_DBG("event happend: pinnum: %d, ev: %s", db->pin, ev_tbl[ev]);
|
||||
|
||||
button_event_t event = {
|
||||
.pin = db->pin,
|
||||
.event = ev,
|
||||
};
|
||||
|
||||
os_queue_send(&s_event_queue, &event, 0);
|
||||
|
||||
button_callback_t *tmp = g_callback_list_head;
|
||||
button_callback_t *callback_list = NULL;
|
||||
button_callback_t *callback_list_it = NULL;
|
||||
while (tmp != NULL)
|
||||
{
|
||||
if (tmp->pin == db->pin)
|
||||
{
|
||||
button_callback_t *new_callback = NULL;
|
||||
if (callback_list == NULL)
|
||||
{
|
||||
callback_list = os_malloc(sizeof(button_callback_t));
|
||||
callback_list_it = callback_list;
|
||||
new_callback = callback_list_it;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_callback = os_malloc(sizeof(button_callback_t));
|
||||
}
|
||||
new_callback->pin = db->pin;
|
||||
new_callback->event_callback = tmp->event_callback;
|
||||
new_callback->next = NULL;
|
||||
|
||||
if (new_callback != callback_list_it)
|
||||
{
|
||||
callback_list_it->next = new_callback;
|
||||
callback_list_it = new_callback;
|
||||
}
|
||||
}
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
tmp = callback_list;
|
||||
int stop_forward_event = 0;
|
||||
while (tmp != NULL)
|
||||
{
|
||||
if (tmp->pin == db->pin)
|
||||
{
|
||||
SYS_LOG_DBG("do call back: pinnum: %d, ev: %s", db->pin, ev_tbl[ev]);
|
||||
stop_forward_event = tmp->event_callback(&event);
|
||||
if (stop_forward_event)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
// 释放临时遍历对象
|
||||
tmp = callback_list;
|
||||
while (tmp)
|
||||
{
|
||||
button_callback_t *next_obj = tmp->next;
|
||||
|
||||
os_free(tmp);
|
||||
tmp = next_obj;
|
||||
}
|
||||
|
||||
return stop_forward_event;
|
||||
}
|
||||
|
||||
static int update_debounce_counter(int pin_index)
|
||||
{
|
||||
debounce_t *button_event_info = &debounce[pin_index];
|
||||
int level = gpio_get_level(button_event_info->pin);
|
||||
if (button_event_info->current_voltage != level)
|
||||
{
|
||||
button_event_info->debounce_check_counter += 1;
|
||||
}
|
||||
else if (button_event_info->current_voltage == level && button_event_info->debounce_check_counter > 0)
|
||||
{
|
||||
button_event_info->debounce_check_counter -= 1;
|
||||
}
|
||||
|
||||
// 防抖检测已经连续多次检测到相同的电平,则改变按钮当前的电平
|
||||
if (button_event_info->debounce_check_counter == DEBOUCE_CHECK_MAX_TIMES)
|
||||
{
|
||||
button_event_info->current_voltage = level;
|
||||
button_event_info->debounce_check_counter = 0;
|
||||
SYS_LOG_DBG("button voltage changed, pin:%d, voltage:%d", button_event_info->pin, level);
|
||||
return DEBOUNCE_CHECK_VOLTAGE_CHANGED;
|
||||
}
|
||||
|
||||
return DEBOUNCE_CHECK_VOLTAGE_DID_NOT_CHANGED;
|
||||
}
|
||||
|
||||
static bool is_button_down(int pin_index)
|
||||
{
|
||||
debounce_t *button_event_info = &debounce[pin_index];
|
||||
|
||||
if (button_event_info->is_inverted && button_event_info->current_voltage == VOLTAGE_LOW)
|
||||
{
|
||||
// 如果电平是反向的,并且当前是低电平,则认为按钮按下了
|
||||
return true;
|
||||
}
|
||||
else if (!button_event_info->is_inverted && button_event_info->current_voltage == VOLTAGE_HIGH)
|
||||
{
|
||||
// 如果电平不是反向的,并且当前是高电平,则认为按钮按下了
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool is_button_up(int pin_index)
|
||||
{
|
||||
debounce_t *button_event_info = &debounce[pin_index];
|
||||
|
||||
if (button_event_info->is_inverted && button_event_info->current_voltage == VOLTAGE_HIGH)
|
||||
{
|
||||
// 如果电平是反向的,并且当前是高电平,则认为按钮释放了
|
||||
return true;
|
||||
}
|
||||
else if (!button_event_info->is_inverted && button_event_info->current_voltage == VOLTAGE_LOW)
|
||||
{
|
||||
// 如果电平不是反向的,并且当前是低电平,则认为按钮释放了
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void _work_handler_button(void *pvParameter)
|
||||
{
|
||||
static uint8_t cancel_laster_event = 1;
|
||||
|
||||
for (int idx = 0; idx < pin_count; idx++)
|
||||
{
|
||||
debounce_t *button_event_info = &debounce[idx];
|
||||
|
||||
int check_result = update_debounce_counter(idx); // 防抖处理
|
||||
if (check_result == DEBOUNCE_CHECK_VOLTAGE_DID_NOT_CHANGED)
|
||||
{
|
||||
// 如果allow_multiple_long_press_event为false,则一次长按无论长按多久,只会触发一次长按事件
|
||||
if (!button_event_info->allow_multiple_long_press_event && button_event_info->long_press_event_sent != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// 电平没有变化,则检查按钮是否已经按下,以开始检查长按操作
|
||||
if (button_event_info->down_time && millis() >= button_event_info->next_long_time)
|
||||
{
|
||||
button_event_info->next_long_time = millis() + LONG_PRESS_REPEAT;
|
||||
button_event_info->long_press_event_sent = 1;
|
||||
cancel_laster_event = send_event(&debounce[idx], BUTTON_HELD);
|
||||
if (cancel_laster_event)
|
||||
{
|
||||
button_event_info->down_time = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 电平有变化,检查是按下还是松开
|
||||
if (button_event_info->down_time == 0 && is_button_down(idx))
|
||||
{
|
||||
cancel_laster_event = 0;
|
||||
SYS_LOG_DBG("update downtime for pin:%d", button_event_info->pin);
|
||||
button_event_info->down_time = millis();
|
||||
button_event_info->next_long_time = button_event_info->down_time + LONG_PRESS_DURATION;
|
||||
cancel_laster_event = send_event(&debounce[idx], BUTTON_DOWN);
|
||||
if (cancel_laster_event)
|
||||
{
|
||||
button_event_info->down_time = 0;
|
||||
}
|
||||
}
|
||||
else if (button_event_info->down_time && is_button_up(idx))
|
||||
{
|
||||
button_event_info->down_time = 0;
|
||||
button_event_info->long_press_event_sent = 0;
|
||||
cancel_laster_event = send_event(&debounce[idx], BUTTON_UP);
|
||||
if (cancel_laster_event)
|
||||
{
|
||||
button_event_info->down_time = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
os_work_later(10);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 初始化按电平式的按键检测。
|
||||
* 这将创建一个用于扫描按键的线程,当检测到按键变化时,将在线程中产生两种通知:
|
||||
* 1. 发送到内部创建的队列中(提示:如果使用了 os_queue_regist() 注册工作项,该工作项将被自动唤醒)
|
||||
* 2. 执行由 button_event_add_callback() 设置的回调函数(提示:同一引脚可设置多个回调)
|
||||
*
|
||||
* @param pin_select 按位表示 MCU 的引脚呈
|
||||
* @param en_lev 触发电平
|
||||
* @return os_queue_t* 由内部创建的消息队列
|
||||
*/
|
||||
os_queue_t *button_init(unsigned long long pin_select, uint8_t en_lev)
|
||||
{
|
||||
return _pulled_button_init(pin_select, en_lev == 0 ? GPIO_PULLUP_ONLY : GPIO_PULLDOWN_ONLY);
|
||||
}
|
||||
|
||||
static os_queue_t *_pulled_button_init(unsigned long long pin_select, gpio_pull_mode_t pull_mode)
|
||||
{
|
||||
if (pin_count != -1)
|
||||
{
|
||||
SYS_LOG_WRN("Already initialized");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Configure the pins
|
||||
gpio_config_t io_conf;
|
||||
io_conf.mode = GPIO_MODE_INPUT;
|
||||
io_conf.pull_up_en = (pull_mode == GPIO_PULLUP_ONLY || pull_mode == GPIO_PULLUP_PULLDOWN);
|
||||
io_conf.pull_down_en = (pull_mode == GPIO_PULLDOWN_ONLY || pull_mode == GPIO_PULLUP_PULLDOWN);
|
||||
io_conf.pin_bit_mask = pin_select;
|
||||
io_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
gpio_config(&io_conf);
|
||||
|
||||
// Scan the pin map to determine number of pins
|
||||
pin_count = 0;
|
||||
int pin = 0;
|
||||
for (pin = 0; pin < sizeof(pin_select) * 8; pin++)
|
||||
{
|
||||
if ((1ULL << pin) & pin_select)
|
||||
{
|
||||
pin_count++;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize global state and s_event_queue
|
||||
debounce = os_calloc(sizeof(debounce_t) * pin_count);
|
||||
// s_event_queue = xQueueCreate(4, sizeof(button_event_t));
|
||||
os_queue_create(&s_event_queue, 4, sizeof(button_event_t));
|
||||
|
||||
// Scan the pin map to determine each pin number, populate the state
|
||||
uint32_t idx = 0;
|
||||
for (pin = 0; pin < sizeof(pin_select) * 8; pin++)
|
||||
{
|
||||
if ((1ULL << pin) & pin_select)
|
||||
{
|
||||
SYS_LOG_DBG("Registering button input: %d", pin);
|
||||
debounce_t *button_event_info = &debounce[idx];
|
||||
|
||||
button_event_info->pin = pin;
|
||||
button_event_info->down_time = 0;
|
||||
button_event_info->allow_multiple_long_press_event = 1;
|
||||
button_event_info->is_inverted = (pull_mode == GPIO_PULLUP_ONLY);
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
os_work_create(&s_work_hdl, "", _work_handler_button, NULL, OS_PRIORITY_HIGHEST);
|
||||
os_work_submit(default_os_work_q_hdl, &s_work_hdl, 1000);
|
||||
|
||||
SYS_LOG_INF("Initialized");
|
||||
|
||||
return &s_event_queue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 添加回调函数:当由 button_init() 设置的对应的引脚号产生按键状态变化时,由内部线程创建执行的回调函数。
|
||||
*
|
||||
* @param pin 0..n
|
||||
* @param callback int (*)(const button_event_t *event)
|
||||
*/
|
||||
void button_event_add_callback(uint32_t pin, BUTTON_EVENT_CALLBACK callback)
|
||||
{
|
||||
button_callback_t *callback_obj = os_malloc(sizeof(button_callback_t));
|
||||
callback_obj->pin = pin;
|
||||
callback_obj->event_callback = callback;
|
||||
callback_obj->next = NULL;
|
||||
if (g_callback_list_head == NULL)
|
||||
{
|
||||
g_callback_list_head = callback_obj;
|
||||
g_callback_list_tail = g_callback_list_head;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_callback_list_tail->next = callback_obj;
|
||||
g_callback_list_tail = callback_obj;
|
||||
}
|
||||
}
|
||||
|
||||
void button_event_remove_callback(uint32_t pin, BUTTON_EVENT_CALLBACK callback)
|
||||
{
|
||||
button_callback_t *tmp = g_callback_list_head;
|
||||
button_callback_t *previous_item = NULL;
|
||||
SYS_LOG_DBG("remove pin:%d", pin);
|
||||
while (tmp != NULL)
|
||||
{
|
||||
if (tmp->event_callback == callback && tmp->pin == pin)
|
||||
{
|
||||
if (previous_item)
|
||||
{
|
||||
previous_item->next = tmp->next; // 断开当前点节,并将前一个和后一个连接起来
|
||||
os_free(tmp);
|
||||
SYS_LOG_DBG("found item");
|
||||
tmp = previous_item->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 没有上一个节点,则将头部节点,设置为待移除节点的下一个节点
|
||||
if (tmp->next)
|
||||
{
|
||||
g_callback_list_head = tmp->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_callback_list_head = NULL;
|
||||
SYS_LOG_DBG("####!!!!#####!!!!");
|
||||
}
|
||||
os_free(tmp);
|
||||
tmp = g_callback_list_head;
|
||||
SYS_LOG_DBG("case111");
|
||||
}
|
||||
SYS_LOG_DBG("2222");
|
||||
}
|
||||
else
|
||||
{
|
||||
previous_item = tmp;
|
||||
tmp = tmp->next;
|
||||
SYS_LOG_DBG("1111");
|
||||
}
|
||||
}
|
||||
|
||||
// 更新g_callback_list_tail指针
|
||||
while (tmp != NULL)
|
||||
{
|
||||
g_callback_list_tail = tmp;
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
SYS_LOG_DBG("doneeee1");
|
||||
}
|
||||
47
app/button/button_event.h
Normal file
47
app/button/button_event.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* @file button_event.h
|
||||
* @author your name (you@domain.com)
|
||||
* @brief
|
||||
* @version 0.1
|
||||
* @date 2023-09-04
|
||||
*
|
||||
* @copyright Copyright (c) 2023
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "os/os.h"
|
||||
#include "driver/gpio.h"
|
||||
|
||||
#define PIN_BIT(x) (1ULL << x)
|
||||
|
||||
#define LONG_PRESS_DURATION (1000)
|
||||
#define LONG_PRESS_REPEAT (200)
|
||||
|
||||
typedef enum
|
||||
{
|
||||
BUTTON_UP,
|
||||
BUTTON_DOWN,
|
||||
BUTTON_HELD
|
||||
} button_event_e;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t pin;
|
||||
button_event_e event;
|
||||
} button_event_t;
|
||||
|
||||
typedef int (*BUTTON_EVENT_CALLBACK)(const button_event_t *event);
|
||||
|
||||
typedef struct button_callback_s
|
||||
{
|
||||
struct button_callback_s *next;
|
||||
uint32_t pin;
|
||||
BUTTON_EVENT_CALLBACK event_callback;
|
||||
} button_callback_t;
|
||||
|
||||
os_queue_t *button_init(unsigned long long pin_select, uint8_t en_lev);
|
||||
|
||||
void button_event_add_callback(uint32_t pin, BUTTON_EVENT_CALLBACK callback);
|
||||
void button_event_remove_callback(uint32_t pin, BUTTON_EVENT_CALLBACK callback);
|
||||
27
app/config/board_config.c
Normal file
27
app/config/board_config.c
Normal file
@@ -0,0 +1,27 @@
|
||||
#include "board_config.h"
|
||||
|
||||
#include "driver/uart.h"
|
||||
|
||||
#define CONFIG_SYS_LOG_LEVEL SYS_LOG_LEVEL_DBG
|
||||
#define SYS_LOG_DOMAIN "CFG"
|
||||
#define CONS_ABORT()
|
||||
#include "sys_log.h"
|
||||
|
||||
static cfg_board_t const s_cfg_board_default = {
|
||||
/* 控制台串口 */
|
||||
.uart_console = {
|
||||
.pin_txd = {43, _GPIO_DIR_OUT, _GPIO_PUD_PULL_UP},
|
||||
.pin_rxd = {44, _GPIO_DIR_IN, _GPIO_PUD_PULL_UP},
|
||||
.id = UART_NUM_0,
|
||||
.irq_prior = 0,
|
||||
.br = 115200,
|
||||
},
|
||||
|
||||
/* 启动按键 */
|
||||
.key_boot = {
|
||||
.pin = 9, // 用于切换灯效
|
||||
.en_lev = 0, // 用于切换灯效
|
||||
},
|
||||
};
|
||||
|
||||
const cfg_board_t *g_cfg_board = &s_cfg_board_default;
|
||||
40
app/config/board_config.h
Normal file
40
app/config/board_config.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* @file board_config.h
|
||||
* @author LokLiang
|
||||
* @brief 统一板载硬件描述数据结构
|
||||
* @version 0.1
|
||||
* @date 2023-11-24
|
||||
*
|
||||
* @copyright Copyright (c) 2023
|
||||
*
|
||||
* 目的与作用场景:
|
||||
* 使同类型的固件适应不同的硬件版本。
|
||||
* 例如同一类型产品,即使某些功能引脚改动,依然可以根据配置文件正确引导程序,而不需要新增特定的固件版本,旧的产品依然得到长期的支持。
|
||||
*
|
||||
* 数据设置:
|
||||
* 只能在工厂中配置,除此之外不允许任何手段尝试修改。
|
||||
* 数据地址固定为分区配置中
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "drivers/chip/_hal.h"
|
||||
|
||||
typedef struct // 按键配置
|
||||
{
|
||||
uint8_t pin; // 引脚号
|
||||
uint8_t en_lev; // 触发电平
|
||||
} cfg_board_key_t;
|
||||
|
||||
typedef struct // 数据结构一旦定下不可随意变更
|
||||
{
|
||||
/* 硬件描述类 */
|
||||
hal_uart_hdl_t uart_console; // 控制台
|
||||
cfg_board_key_t key_boot; // 启动按键
|
||||
|
||||
/* 产品功能描述类 */
|
||||
|
||||
} cfg_board_t;
|
||||
|
||||
extern const cfg_board_t *g_cfg_board; // 配置数据
|
||||
40
app/config/board_config/bec_led_strip_esp32c3.h
Normal file
40
app/config/board_config/bec_led_strip_esp32c3.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#if (CONFIG_BOARD_NAME_BEC_LED_STRIP_ESP32C3)
|
||||
|
||||
#define CONFIG_IDF_TARGET "esp32c3" /* 警告:请使用命令 idf.py set-target <参数> 选择对应的平台 */
|
||||
|
||||
static cfg_board_t const s_cfg_board_default = {
|
||||
.firmware_str = PRODUCT_TYPE,
|
||||
.platform_str = CONFIG_IDF_TARGET,
|
||||
.board_name = "bec_led_strip_esp32c3",
|
||||
|
||||
/* 控制台串口 */
|
||||
.uart_console = {
|
||||
.pin_txd = {43, _GPIO_DIR_OUT, _GPIO_PUD_PULL_UP},
|
||||
.pin_rxd = {44, _GPIO_DIR_IN, _GPIO_PUD_PULL_UP},
|
||||
.id = UART_NUM_0,
|
||||
.irq_prior = 0,
|
||||
.br = 115200,
|
||||
},
|
||||
|
||||
/* 数据透传串口 */
|
||||
.uart_fc = {
|
||||
.pin_txd = {3, _GPIO_DIR_OUT, _GPIO_PUD_PULL_UP},
|
||||
.pin_rxd = {5, _GPIO_DIR_IN, _GPIO_PUD_PULL_UP},
|
||||
.id = UART_NUM_1,
|
||||
.irq_prior = 24,
|
||||
.br = 115200,
|
||||
},
|
||||
|
||||
.led_spi = {
|
||||
.spi_id = SPI2_HOST, // 模拟 PWM 用的 SPI
|
||||
.pin = 18, // 模拟 PWM 输出引脚
|
||||
},
|
||||
|
||||
/* 启动按键 */
|
||||
.key_boot = {
|
||||
.pin = 7, // 用于切换灯效
|
||||
.en_lev = 1, // 用于切换灯效
|
||||
},
|
||||
};
|
||||
|
||||
#endif
|
||||
40
app/config/board_config/devkit_esp32c2.h
Normal file
40
app/config/board_config/devkit_esp32c2.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#if (CONFIG_BOARD_NAME_DEVKIT_ESP32C2)
|
||||
|
||||
#define CONFIG_IDF_TARGET "esp32c2" /* 警告:请使用命令 idf.py set-target <参数> 选择对应的平台 */
|
||||
|
||||
static cfg_board_t const s_cfg_board_default = {
|
||||
.firmware_str = PRODUCT_TYPE,
|
||||
.platform_str = CONFIG_IDF_TARGET,
|
||||
.board_name = "devkit_esp32c2",
|
||||
|
||||
/* 控制台串口 */
|
||||
.uart_console = {
|
||||
.pin_txd = {43, _GPIO_DIR_OUT, _GPIO_PUD_PULL_UP},
|
||||
.pin_rxd = {44, _GPIO_DIR_IN, _GPIO_PUD_PULL_UP},
|
||||
.id = UART_NUM_0,
|
||||
.irq_prior = 0,
|
||||
.br = 115200,
|
||||
},
|
||||
|
||||
/* 数据透传串口 */
|
||||
.uart_fc = {
|
||||
.pin_txd = {7, _GPIO_DIR_OUT, _GPIO_PUD_PULL_UP},
|
||||
.pin_rxd = {6, _GPIO_DIR_IN, _GPIO_PUD_PULL_UP},
|
||||
.id = UART_NUM_1,
|
||||
.irq_prior = 24,
|
||||
.br = 115200,
|
||||
},
|
||||
|
||||
.led_spi = {
|
||||
.spi_id = SPI2_HOST, // 模拟 PWM 用的 SPI
|
||||
.pin = 1, // 模拟 PWM 输出引脚
|
||||
},
|
||||
|
||||
/* 启动按键 */
|
||||
.key_boot = {
|
||||
.pin = 9, // 用于切换灯效
|
||||
.en_lev = 0, // 用于切换灯效
|
||||
},
|
||||
};
|
||||
|
||||
#endif
|
||||
40
app/config/board_config/devkit_esp32c3.h
Normal file
40
app/config/board_config/devkit_esp32c3.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#if (CONFIG_BOARD_NAME_DEVKIT_ESP32C3)
|
||||
|
||||
#define CONFIG_IDF_TARGET "esp32c3" /* 警告:请使用命令 idf.py set-target <参数> 选择对应的平台 */
|
||||
|
||||
static cfg_board_t const s_cfg_board_default = {
|
||||
.firmware_str = PRODUCT_TYPE,
|
||||
.platform_str = CONFIG_IDF_TARGET,
|
||||
.board_name = "devkit_esp32c3",
|
||||
|
||||
/* 控制台串口 */
|
||||
.uart_console = {
|
||||
.pin_txd = {43, _GPIO_DIR_OUT, _GPIO_PUD_PULL_UP},
|
||||
.pin_rxd = {44, _GPIO_DIR_IN, _GPIO_PUD_PULL_UP},
|
||||
.id = UART_NUM_0,
|
||||
.irq_prior = 0,
|
||||
.br = 115200,
|
||||
},
|
||||
|
||||
/* 数据透传串口 */
|
||||
.uart_fc = {
|
||||
.pin_txd = {7, _GPIO_DIR_OUT, _GPIO_PUD_PULL_UP},
|
||||
.pin_rxd = {6, _GPIO_DIR_IN, _GPIO_PUD_PULL_UP},
|
||||
.id = UART_NUM_1,
|
||||
.irq_prior = 24,
|
||||
.br = 115200,
|
||||
},
|
||||
|
||||
.led_spi = {
|
||||
.spi_id = SPI2_HOST, // 模拟 PWM 用的 SPI
|
||||
.pin = 10, // 模拟 PWM 输出引脚
|
||||
},
|
||||
|
||||
/* 启动按键 */
|
||||
.key_boot = {
|
||||
.pin = 9, // 用于切换灯效
|
||||
.en_lev = 0, // 用于切换灯效
|
||||
},
|
||||
};
|
||||
|
||||
#endif
|
||||
40
app/config/board_config/fixedwing_new.h
Normal file
40
app/config/board_config/fixedwing_new.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#if (CONFIG_BOARD_NAME_FIXEDWING_NEW)
|
||||
|
||||
#define CONFIG_IDF_TARGET "esp32c2" /* 警告:请使用命令 idf.py set-target <参数> 选择对应的平台 */
|
||||
|
||||
static cfg_board_t const s_cfg_board_default = {
|
||||
.firmware_str = PRODUCT_TYPE,
|
||||
.platform_str = CONFIG_IDF_TARGET,
|
||||
.board_name = "fixedwing_new",
|
||||
|
||||
/* 控制台串口 */
|
||||
.uart_console = {
|
||||
.pin_txd = {43, _GPIO_DIR_OUT, _GPIO_PUD_PULL_UP},
|
||||
.pin_rxd = {44, _GPIO_DIR_IN, _GPIO_PUD_PULL_UP},
|
||||
.id = UART_NUM_0,
|
||||
.irq_prior = 0,
|
||||
.br = 115200,
|
||||
},
|
||||
|
||||
/* 数据透传串口 */
|
||||
.uart_fc = {
|
||||
.pin_txd = {7, _GPIO_DIR_OUT, _GPIO_PUD_PULL_UP},
|
||||
.pin_rxd = {6, _GPIO_DIR_IN, _GPIO_PUD_PULL_UP},
|
||||
.id = UART_NUM_1,
|
||||
.irq_prior = 24,
|
||||
.br = 115200,
|
||||
},
|
||||
|
||||
.led_spi = {
|
||||
.spi_id = SPI2_HOST, // 模拟 PWM 用的 SPI
|
||||
.pin = 1, // 模拟 PWM 输出引脚
|
||||
},
|
||||
|
||||
/* 启动按键 */
|
||||
.key_boot = {
|
||||
.pin = 3, // 用于切换灯效
|
||||
.en_lev = 1, // 用于切换灯效
|
||||
},
|
||||
};
|
||||
|
||||
#endif
|
||||
40
app/config/board_config/fixedwing_old.h
Normal file
40
app/config/board_config/fixedwing_old.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#if (CONFIG_BOARD_NAME_FIXEDWING_OLD)
|
||||
|
||||
#define CONFIG_IDF_TARGET "esp32c2" /* 警告:请使用命令 idf.py set-target <参数> 选择对应的平台 */
|
||||
|
||||
static cfg_board_t const s_cfg_board_default = {
|
||||
.firmware_str = PRODUCT_TYPE,
|
||||
.platform_str = CONFIG_IDF_TARGET,
|
||||
.board_name = "fixedwing_old",
|
||||
|
||||
/* 控制台串口 */
|
||||
.uart_console = {
|
||||
.pin_txd = {43, _GPIO_DIR_OUT, _GPIO_PUD_PULL_UP},
|
||||
.pin_rxd = {44, _GPIO_DIR_IN, _GPIO_PUD_PULL_UP},
|
||||
.id = UART_NUM_0,
|
||||
.irq_prior = 0,
|
||||
.br = 115200,
|
||||
},
|
||||
|
||||
/* 数据透传串口 */
|
||||
.uart_fc = {
|
||||
.pin_txd = {8, _GPIO_DIR_OUT, _GPIO_PUD_PULL_UP},
|
||||
.pin_rxd = {7, _GPIO_DIR_IN, _GPIO_PUD_PULL_UP},
|
||||
.id = UART_NUM_1,
|
||||
.irq_prior = 24,
|
||||
.br = 115200,
|
||||
},
|
||||
|
||||
.led_spi = {
|
||||
.spi_id = SPI2_HOST, // 模拟 PWM 用的 SPI
|
||||
.pin = 1, // 模拟 PWM 输出引脚
|
||||
},
|
||||
|
||||
/* 启动按键 */
|
||||
.key_boot = {
|
||||
.pin = 3, // 用于切换灯效
|
||||
.en_lev = 1, // 用于切换灯效
|
||||
},
|
||||
};
|
||||
|
||||
#endif
|
||||
158
app/console.c
Normal file
158
app/console.c
Normal file
@@ -0,0 +1,158 @@
|
||||
#include "driver/uart.h"
|
||||
#include "console.h"
|
||||
#include "shell/sh.h"
|
||||
#include "os/os.h"
|
||||
#include "drivers/chip/uart.h"
|
||||
#include "config/board_config.h"
|
||||
#include "sys_log.h"
|
||||
|
||||
static shell_input_cb s_input_cb;
|
||||
|
||||
static void initialize_console(void)
|
||||
{
|
||||
/* Drain stdout before reconfiguring it */
|
||||
fflush(stdout);
|
||||
|
||||
/* Disable buffering on stdin */
|
||||
setvbuf(stdin, NULL, _IONBF, 0);
|
||||
|
||||
/* Configure UART. Note that REF_TICK is used so that the baud rate remains
|
||||
* correct while APB frequency is changing in light sleep mode.
|
||||
*/
|
||||
const uart_config_t uart_config = {
|
||||
.baud_rate = CONFIG_ESP_CONSOLE_UART_BAUDRATE,
|
||||
.data_bits = UART_DATA_8_BITS,
|
||||
.parity = UART_PARITY_DISABLE,
|
||||
.stop_bits = UART_STOP_BITS_1,
|
||||
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
|
||||
.source_clk = UART_SCLK_REF_TICK,
|
||||
#else
|
||||
.source_clk = UART_SCLK_XTAL,
|
||||
#endif
|
||||
};
|
||||
/* Install UART driver for interrupt-driven reads and writes */
|
||||
ESP_ERROR_CHECK(uart_driver_install(CONFIG_ESP_CONSOLE_UART_NUM,
|
||||
256, 0, 0, NULL, 0));
|
||||
ESP_ERROR_CHECK(uart_param_config(CONFIG_ESP_CONSOLE_UART_NUM, &uart_config));
|
||||
}
|
||||
|
||||
static void _work_sh(void *arg)
|
||||
{
|
||||
char c;
|
||||
int flag = 0;
|
||||
shell_input_cb input_cb = s_input_cb;
|
||||
|
||||
if (input_cb)
|
||||
{
|
||||
static char last_key;
|
||||
while (drv_uart_poll_read(g_cfg_board->uart_console.id, &c) > 0)
|
||||
{
|
||||
if (c != '\n' || last_key != '\r')
|
||||
{
|
||||
input_cb(&g_uart_handle_vt100, c);
|
||||
flag = 1;
|
||||
}
|
||||
last_key = c;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (drv_uart_poll_read(g_cfg_board->uart_console.id, &c) > 0)
|
||||
{
|
||||
sh_putc(&g_uart_handle_vt100, c);
|
||||
flag = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (flag)
|
||||
{
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
os_work_later(10);
|
||||
}
|
||||
|
||||
static int _port_sh_vprint_fn(const char *format, va_list va)
|
||||
{
|
||||
return vprintf(format, va);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 启动 shell.
|
||||
* 这将:
|
||||
* 1. 执行对应的初始化
|
||||
* 2. 自动默认工作队列中创建一个解析数据的后台
|
||||
*/
|
||||
void shell_start(void)
|
||||
{
|
||||
static uint8_t start_flag = 0;
|
||||
|
||||
if (start_flag == 0)
|
||||
{
|
||||
/* 初始化控制台串口 */
|
||||
initialize_console();
|
||||
|
||||
/* 执行 shell 内部的初始化 */
|
||||
sh_register_external(_port_sh_vprint_fn);
|
||||
|
||||
/* 注册系统命令 */
|
||||
extern void soc_shell_register(void);
|
||||
soc_shell_register();
|
||||
|
||||
/* 创建 shell 的接收任务 _work_sh() */
|
||||
static os_work_t work_handler_shell;
|
||||
os_work_create(&work_handler_shell, "work-shell", _work_sh, NULL, 1);
|
||||
os_work_submit(default_os_work_q_hdl, &work_handler_shell, 0);
|
||||
|
||||
/* 设置 shell 的提示符 */
|
||||
g_uart_handle_vt100.disable_echo = !CONFIG_SYS_LOG_CONS_ON; // 关闭回显
|
||||
sh_putstr_quiet(&g_uart_handle_vt100, "sh version\r");
|
||||
sh_set_prompt(&g_uart_handle_vt100, "esp32:/> ");
|
||||
sh_putc(&g_uart_handle_vt100, '\r');
|
||||
fflush(stdout);
|
||||
|
||||
start_flag = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 临时改变终端的输入接口。
|
||||
* 使用 shell_input_restore() 可恢复预设的接口
|
||||
*
|
||||
* @param cb 输入接口
|
||||
*/
|
||||
void shell_input_set(shell_input_cb cb)
|
||||
{
|
||||
s_input_cb = cb;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 恢复 shell_input_set() 被执行前的设置
|
||||
*
|
||||
*/
|
||||
void shell_input_restore(void)
|
||||
{
|
||||
s_input_cb = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 在执行命令的过程中使用。
|
||||
* 若被执行的命令需要循环执行时,使用这个函数将读取控制台收到的数据,
|
||||
* 当收到 ESC 按键时返回真值,此时可退出该命令的执行函数
|
||||
*
|
||||
* @retval true 按下了 ESC 键
|
||||
* @retval false 未按下 ESC 键
|
||||
*/
|
||||
bool shell_is_aobrt(void)
|
||||
{
|
||||
char c;
|
||||
if (drv_uart_poll_read(g_cfg_board->uart_console.id, &c) > 0)
|
||||
{
|
||||
if (c == '\x1b')
|
||||
{
|
||||
fflush(stdout);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
16
app/console.h
Normal file
16
app/console.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef __CONSOLE_H__
|
||||
#define __CONSOLE_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "shell/sh.h"
|
||||
|
||||
typedef void (*shell_input_cb)(sh_t *sh_hdl, char c);
|
||||
|
||||
void shell_start();
|
||||
|
||||
void shell_input_set(shell_input_cb cb);
|
||||
void shell_input_restore(void);
|
||||
|
||||
bool shell_is_aobrt(void);
|
||||
|
||||
#endif
|
||||
249
app/drivers/data_port/sb_data_port.c
Executable file
249
app/drivers/data_port/sb_data_port.c
Executable file
@@ -0,0 +1,249 @@
|
||||
#include "drivers/data_port/sb_data_port.h"
|
||||
|
||||
#include "os/os.h"
|
||||
|
||||
#define CONFIG_SYS_LOG_LEVEL SYS_LOG_LEVEL_INF
|
||||
#define SYS_LOG_DOMAIN "DATA"
|
||||
#define CONS_ABORT()
|
||||
#include "sys_log.h"
|
||||
|
||||
/**
|
||||
* @brief 由具体驱动实现的,以达到节省资源为主要目的,启动数据接口
|
||||
*
|
||||
* @param port 由对应的驱动提供的绑定接口获得的句柄
|
||||
* @retval 0 成功
|
||||
*/
|
||||
int sb_data_port_start(sb_data_port_t *port)
|
||||
{
|
||||
if (sb_data_port_is_started(port))
|
||||
{
|
||||
SYS_LOG_WRN("Data interface repeat started");
|
||||
return 0;
|
||||
}
|
||||
if (port == NULL || port->vtable == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (port->vtable->start)
|
||||
{
|
||||
return port->vtable->start(port);
|
||||
}
|
||||
else
|
||||
{
|
||||
SYS_LOG_ERR("The data interface has not been defined");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 由具体驱动实现的,以达到节省资源为主要目的,关闭数据接口
|
||||
*
|
||||
* @param port 由对应的驱动提供的绑定接口获得的句柄
|
||||
* @retval 0 成功
|
||||
*/
|
||||
int sb_data_port_stop(sb_data_port_t *port)
|
||||
{
|
||||
if (!sb_data_port_is_started(port))
|
||||
{
|
||||
SYS_LOG_WRN("The data interface has not been started yet");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (port->vtable->stop)
|
||||
{
|
||||
return port->vtable->stop(port);
|
||||
}
|
||||
else
|
||||
{
|
||||
SYS_LOG_ERR("The data interface has not been defined");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 由具体驱动实现的,写数据到对应的接口。
|
||||
* 建议这些数据将写入到驱动的缓存中,如果 wait_ms 为 0 立即返回,
|
||||
* 如果 wait_ms > 0 则这个时间由本函数计时并处理,但期间可能出现堵塞。
|
||||
* 注意如果有选择 wait_ms > 0 的情况,驱动中收取缓存的线程与应用不能是同一线程。
|
||||
*
|
||||
* @param port 由对应的驱动提供的绑定接口获得的句柄
|
||||
* @param data 来源数据
|
||||
* @param size 数据长度(字节)
|
||||
* @param wait_ms 超时时间(毫秒)
|
||||
* @retval < 0 操作失败或在指定的时间内未满足指定的操作长度
|
||||
* @retval >= 0 实际已缓存的长度
|
||||
*/
|
||||
int sb_data_port_write(sb_data_port_t *port, const void *data, uint32_t size, uint32_t wait_ms)
|
||||
{
|
||||
if (!sb_data_port_is_started(port))
|
||||
{
|
||||
SYS_LOG_WRN("The data interface has not been started yet");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (port->vtable->write)
|
||||
{
|
||||
int ret = 0;
|
||||
int cmp_time = os_get_sys_time();
|
||||
while (size)
|
||||
{
|
||||
int curr_time = os_get_sys_time();
|
||||
int wsize = port->vtable->write(port, data, size);
|
||||
if (wsize > 0)
|
||||
{
|
||||
cmp_time = curr_time;
|
||||
data = &((uint8_t *)data)[wsize];
|
||||
size -= wsize;
|
||||
ret += wsize;
|
||||
}
|
||||
else if (wsize == 0)
|
||||
{
|
||||
if (wait_ms == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (curr_time - cmp_time > wait_ms)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
os_thread_sleep(1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
SYS_LOG_ERR("The data interface has not been defined");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 由具体驱动实现的,从数据接口中读取已缓存的数据。
|
||||
* 如果 wait_ms 为 0 将立即返回,
|
||||
* 如果 wait_ms > 0 则这个时间由本函数计时并处理,期间可能出现堵塞。
|
||||
* 注意如果有选择 wait_ms > 0 的情况,驱动中收取缓存的线程与应用不能是同一线程。
|
||||
*
|
||||
* @param port 由对应的驱动提供的绑定接口获得的句柄
|
||||
* @param buffer[out] 保存到目标内存。值为 NULL 表示仅释放空间
|
||||
* @param length 目标内存长度(字节)
|
||||
* @param wait_ms 超时时间(毫秒)
|
||||
* @retval < 0 操作失败或在指定的时间内未满足指定的操作长度
|
||||
* @retval >= 0 实际已读取的长度
|
||||
*/
|
||||
int sb_data_port_read(sb_data_port_t *port, void *buffer, uint32_t length, uint32_t wait_ms)
|
||||
{
|
||||
if (!sb_data_port_is_started(port))
|
||||
{
|
||||
SYS_LOG_WRN("The data interface has not been started yet");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (port->vtable->read)
|
||||
{
|
||||
int ret = 0;
|
||||
int cmp_time = os_get_sys_time();
|
||||
while (length)
|
||||
{
|
||||
int curr_time = os_get_sys_time();
|
||||
int rsize = port->vtable->read(port, buffer, length);
|
||||
if (rsize > 0)
|
||||
{
|
||||
cmp_time = curr_time;
|
||||
buffer = &((uint8_t *)buffer)[rsize];
|
||||
length -= rsize;
|
||||
ret += rsize;
|
||||
}
|
||||
else if (rsize == 0)
|
||||
{
|
||||
if (wait_ms == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (curr_time - cmp_time > wait_ms)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
os_thread_sleep(1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
SYS_LOG_ERR("The data interface has not been defined");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 由具体驱动实现的,获取当前数据接口是否可用(是否已启动)。
|
||||
* 本套接口内部的所有其他接口内部都会优先经过这个接口确认状态,驱动内部的其他接口不需要二次确认。
|
||||
*
|
||||
* @param port 由对应的驱动提供的绑定接口获得的句柄
|
||||
* @retval true 接口已启动并可用
|
||||
* @retval false 接口未启动,不可用
|
||||
*/
|
||||
bool sb_data_port_is_started(sb_data_port_t *port)
|
||||
{
|
||||
SYS_ASSERT(port, "Data interface not bound");
|
||||
SYS_ASSERT(port->vtable, "Data interface not bound");
|
||||
|
||||
if (port == NULL || port->vtable == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (port->vtable->is_started)
|
||||
{
|
||||
return port->vtable->is_started(port);
|
||||
}
|
||||
else
|
||||
{
|
||||
SYS_LOG_ERR("The data interface has not been defined");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 由具体驱动实现的,获取当前数据接口的本次可读长度
|
||||
*
|
||||
* @param port 由对应的驱动提供的绑定接口获得的句柄
|
||||
* @retval uint32_t sb_data_port_read() 当前可读取的接收缓存长度
|
||||
*/
|
||||
uint32_t sb_data_port_get_rx_length(sb_data_port_t *port)
|
||||
{
|
||||
if (!sb_data_port_is_started(port))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (port->vtable->get_rx_length)
|
||||
{
|
||||
return port->vtable->get_rx_length(port);
|
||||
}
|
||||
else
|
||||
{
|
||||
SYS_LOG_ERR("The data interface has not been defined");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
42
app/drivers/data_port/sb_data_port.h
Executable file
42
app/drivers/data_port/sb_data_port.h
Executable file
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* @file sb_data_port.h
|
||||
* @author LokLiang
|
||||
* @brief 统一的数据接口定义
|
||||
* @version 0.1
|
||||
* @date 2023-11-14
|
||||
*
|
||||
* @copyright Copyright (c) 2023
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct sb_data_port_s sb_data_port_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int (*start)(sb_data_port_t *port); // 由具体驱动实现的,以达到节省资源为主要目的,启动数据接口
|
||||
int (*stop)(sb_data_port_t *port); // 由具体驱动实现的,以达到节省资源为主要目的,关闭数据接口
|
||||
int (*write)(sb_data_port_t *port, const void *data, uint32_t size); // 由具体驱动实现的,写数据到对应的接口。
|
||||
int (*read)(sb_data_port_t *port, void *buffer, uint32_t length); // 由具体驱动实现的,从数据接口中读取已缓存的数据。
|
||||
bool (*is_started)(sb_data_port_t *port); // 由具体驱动实现的,获取当前数据接口是否可用(是否已启动)
|
||||
uint32_t (*get_rx_length)(sb_data_port_t *port); // 由具体驱动实现的,获取当前数据接口的本次可读长度
|
||||
} sb_data_port_vtable_t;
|
||||
|
||||
struct sb_data_port_s
|
||||
{
|
||||
const sb_data_port_vtable_t *vtable; // 接口
|
||||
void *data; // 数据
|
||||
};
|
||||
|
||||
int sb_data_port_start(sb_data_port_t *port);
|
||||
int sb_data_port_stop(sb_data_port_t *port);
|
||||
|
||||
int sb_data_port_write(sb_data_port_t *port, const void *data, uint32_t size, uint32_t wait_ms);
|
||||
int sb_data_port_read(sb_data_port_t *port, void *buffer, uint32_t length, uint32_t wait_ms);
|
||||
|
||||
bool sb_data_port_is_started(sb_data_port_t *port);
|
||||
uint32_t sb_data_port_get_rx_length(sb_data_port_t *port);
|
||||
486
app/drivers/data_port/uart/uart_port.c
Executable file
486
app/drivers/data_port/uart/uart_port.c
Executable file
@@ -0,0 +1,486 @@
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "os/os.h"
|
||||
|
||||
#include "uart_port.h"
|
||||
|
||||
#include "driver/uart.h"
|
||||
|
||||
#include "drivers/data_port/sb_data_port.h"
|
||||
|
||||
#define CONFIG_SYS_LOG_DUMP_ON 0
|
||||
#define CONFIG_SYS_LOG_LEVEL SYS_LOG_LEVEL_WRN
|
||||
#define SYS_LOG_DOMAIN "UART"
|
||||
#include "sys_log.h"
|
||||
|
||||
#define _MAX_UART_NUM 3
|
||||
|
||||
#define UART_IN_TAST_STK_SIZE 2048
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t size;
|
||||
uint8_t data[0];
|
||||
} __fifo_data_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int uart_num;
|
||||
int baudrate;
|
||||
int tx_pin;
|
||||
int rx_pin;
|
||||
int rx_task_priority;
|
||||
uint16_t buffer_size;
|
||||
uint8_t frame_ms;
|
||||
volatile uint16_t buffer_used;
|
||||
os_work_t *rx_resume_work;
|
||||
QueueHandle_t event_queue;
|
||||
os_thread_t rx_thread_hdl;
|
||||
union
|
||||
{
|
||||
os_pipe_t rx_pipe;
|
||||
os_fifo_t rx_fifo;
|
||||
};
|
||||
} __uart_data_t;
|
||||
|
||||
static void _uart_rx_thread(void *parmas)
|
||||
{
|
||||
uart_event_t event;
|
||||
int ret = 0;
|
||||
int len = 0;
|
||||
int rx_len = 0;
|
||||
__uart_data_t *uart_data = ((sb_data_port_t *)parmas)->data;
|
||||
const uint32_t TMP_BUF_LEN = 1024;
|
||||
uint8_t tmpbuffer[TMP_BUF_LEN];
|
||||
TickType_t tick = portMAX_DELAY;
|
||||
uint16_t recv_total = 0;
|
||||
os_time_t rx_time = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (xQueueReceive(uart_data->event_queue, (void *)&event, tick))
|
||||
{
|
||||
switch (event.type)
|
||||
{
|
||||
case UART_DATA:
|
||||
{
|
||||
rx_len = event.size;
|
||||
while (rx_len > 0)
|
||||
{
|
||||
if (uart_data->frame_ms == 0)
|
||||
{
|
||||
len = (rx_len > TMP_BUF_LEN) ? TMP_BUF_LEN : rx_len;
|
||||
ret = uart_read_bytes(uart_data->uart_num, tmpbuffer, len, portMAX_DELAY);
|
||||
if (ret <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
rx_len -= ret;
|
||||
|
||||
// 将数据写入ringbuffer,由外部轮询ringbuffer
|
||||
uint8_t *p = tmpbuffer;
|
||||
for (int i = 0; i < 100 && ret != 0; i++)
|
||||
{
|
||||
int write_result = os_pipe_fifo_fill(&uart_data->rx_pipe, p, ret);
|
||||
p = &((uint8_t *)p)[write_result];
|
||||
ret -= write_result;
|
||||
if (ret != 0)
|
||||
{
|
||||
os_thread_sleep(10);
|
||||
}
|
||||
}
|
||||
if (ret != 0)
|
||||
{
|
||||
SYS_LOG_ERR("write data to rx_pipe_obj failed, remain: %d bytes", ret);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
len = sizeof(tmpbuffer) - recv_total;
|
||||
if (len > rx_len)
|
||||
{
|
||||
len = rx_len;
|
||||
}
|
||||
ret = uart_read_bytes(uart_data->uart_num, &tmpbuffer[recv_total], len, portMAX_DELAY);
|
||||
if (ret <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
rx_len -= ret;
|
||||
recv_total += ret;
|
||||
if (recv_total >= sizeof(tmpbuffer))
|
||||
{
|
||||
rx_time = os_get_sys_time() - uart_data->frame_ms - 1; // 使退出 switch 后的超时条件必定成立而立即保存数据
|
||||
break;
|
||||
}
|
||||
rx_time = os_get_sys_time();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// Event of HW FIFO overflow detected
|
||||
case UART_FIFO_OVF:
|
||||
SYS_LOG_WRN("hw fifo overflow");
|
||||
// If fifo overflow happened, you should consider adding flow control for your application.
|
||||
// The ISR has already reset the rx FIFO,
|
||||
uart_flush_input(uart_data->uart_num);
|
||||
xQueueReset(uart_data->event_queue);
|
||||
break;
|
||||
// Event of UART ring buffer full
|
||||
case UART_BUFFER_FULL:
|
||||
SYS_LOG_WRN("ring buffer full");
|
||||
// If buffer full happened, you should consider encreasing your buffer size
|
||||
uart_flush_input(uart_data->uart_num);
|
||||
xQueueReset(uart_data->event_queue);
|
||||
break;
|
||||
// Event of UART RX break detected
|
||||
case UART_BREAK:
|
||||
SYS_LOG_WRN("uart rx break");
|
||||
break;
|
||||
// Event of UART parity check error
|
||||
case UART_PARITY_ERR:
|
||||
SYS_LOG_WRN("uart parity error");
|
||||
break;
|
||||
// Event of UART frame error
|
||||
case UART_FRAME_ERR:
|
||||
SYS_LOG_WRN("uart frame error");
|
||||
break;
|
||||
// Others
|
||||
default:
|
||||
SYS_LOG_WRN("uart event type: %d", event.type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (uart_data->frame_ms != 0)
|
||||
{
|
||||
if (os_get_sys_time() - rx_time > uart_data->frame_ms)
|
||||
{
|
||||
if (recv_total > 0)
|
||||
{
|
||||
while (uart_data->buffer_used >= uart_data->buffer_size)
|
||||
{
|
||||
os_thread_sleep(1);
|
||||
}
|
||||
|
||||
__fifo_data_t *fifo_data = os_fifo_alloc(sizeof(__fifo_data_t) + recv_total);
|
||||
if (fifo_data)
|
||||
{
|
||||
os_scheduler_suspend();
|
||||
uart_data->buffer_used += recv_total + sizeof(((__fifo_data_t *)0)->size);
|
||||
os_scheduler_resume();
|
||||
|
||||
fifo_data->size = recv_total;
|
||||
memcpy(fifo_data->data, tmpbuffer, recv_total);
|
||||
os_fifo_put(&uart_data->rx_fifo, fifo_data);
|
||||
}
|
||||
|
||||
recv_total = 0;
|
||||
tick = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
tick = portMAX_DELAY;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tick = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void uart_port_initialize(sb_data_port_t *port)
|
||||
{
|
||||
__uart_data_t *uart_data = port->data;
|
||||
uart_config_t uart_config;
|
||||
|
||||
memset(&uart_config, 0, sizeof(uart_config));
|
||||
uart_config.baud_rate = uart_data->baudrate;
|
||||
uart_config.data_bits = UART_DATA_8_BITS;
|
||||
uart_config.parity = UART_PARITY_DISABLE;
|
||||
uart_config.stop_bits = UART_STOP_BITS_1;
|
||||
uart_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE;
|
||||
|
||||
esp_err_t ret = uart_set_pin(uart_data->uart_num, uart_data->tx_pin, uart_data->rx_pin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
|
||||
if (ret != ESP_OK)
|
||||
{
|
||||
SYS_LOG_ERR("failed to set uart pin:%d, %d", uart_data->uart_num, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = uart_param_config(uart_data->uart_num, &uart_config);
|
||||
if (ret != ESP_OK)
|
||||
{
|
||||
SYS_LOG_ERR("failed to set uart param:%d, %d", uart_data->uart_num, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = uart_driver_install(uart_data->uart_num, 0x400, 0x400, 3, &(uart_data->event_queue), 0);
|
||||
if (ret != ESP_OK)
|
||||
{
|
||||
SYS_LOG_ERR("failed to uart_driver_install:%d, %d", uart_data->uart_num, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
SYS_LOG_INF("uart_driver_install ok. (%d, %d, %d, %d, %d, %d)", uart_data->uart_num, 0x400, 0x400, 3, (uint32_t)&uart_data->event_queue, 0);
|
||||
}
|
||||
|
||||
static int _uart_port_start(sb_data_port_t *port)
|
||||
{
|
||||
__uart_data_t *uart_data = port->data;
|
||||
|
||||
SYS_LOG_INF("uart start, uartnum:%d", uart_data->uart_num);
|
||||
|
||||
if (uart_data->frame_ms == 0)
|
||||
{
|
||||
if (!os_pipe_is_valid(&uart_data->rx_pipe))
|
||||
{
|
||||
if (os_pipe_create(&uart_data->rx_pipe, uart_data->buffer_size) != OS_OK)
|
||||
{
|
||||
port->vtable->stop(port);
|
||||
return -1;
|
||||
}
|
||||
os_pipe_regist(&uart_data->rx_pipe, uart_data->rx_resume_work, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!os_fifo_q_is_valid(&uart_data->rx_fifo))
|
||||
{
|
||||
if (os_fifo_q_create(&uart_data->rx_fifo) != OS_OK)
|
||||
{
|
||||
port->vtable->stop(port);
|
||||
return -1;
|
||||
}
|
||||
os_fifo_q_regist(&uart_data->rx_fifo, uart_data->rx_resume_work, 0);
|
||||
}
|
||||
uart_data->buffer_used = 0;
|
||||
}
|
||||
|
||||
if (!uart_is_driver_installed(uart_data->uart_num))
|
||||
{
|
||||
uart_port_initialize(port);
|
||||
}
|
||||
|
||||
if (!os_thread_is_valid(&uart_data->rx_thread_hdl))
|
||||
{
|
||||
if (os_thread_create(&uart_data->rx_thread_hdl,
|
||||
"uart_rx",
|
||||
_uart_rx_thread,
|
||||
port,
|
||||
UART_IN_TAST_STK_SIZE,
|
||||
uart_data->rx_task_priority) != OS_OK)
|
||||
{
|
||||
SYS_LOG_WRN("task create fail");
|
||||
port->vtable->stop(port);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _uart_port_stop(sb_data_port_t *port)
|
||||
{
|
||||
__uart_data_t *uart_data = port->data;
|
||||
|
||||
if (os_thread_is_valid(&uart_data->rx_thread_hdl))
|
||||
{
|
||||
os_thread_delete(&uart_data->rx_thread_hdl);
|
||||
}
|
||||
|
||||
if (uart_is_driver_installed(uart_data->uart_num))
|
||||
{
|
||||
uart_driver_delete(uart_data->uart_num);
|
||||
}
|
||||
|
||||
if (uart_data->frame_ms == 0)
|
||||
{
|
||||
if (os_pipe_is_valid(&uart_data->rx_pipe))
|
||||
{
|
||||
os_pipe_delete(&uart_data->rx_pipe);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (os_fifo_q_is_valid(&uart_data->rx_fifo))
|
||||
{
|
||||
os_fifo_q_delete(&uart_data->rx_fifo);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _uart_port_write(sb_data_port_t *port, const void *data, uint32_t size)
|
||||
{
|
||||
__uart_data_t *uart_data = port->data;
|
||||
int ret = uart_write_bytes(uart_data->uart_num, data, size);
|
||||
if (ret > 0)
|
||||
{
|
||||
SYS_LOG_DUMP(data, ret, 0, 0);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _uart_port_read(sb_data_port_t *port, void *data, uint32_t size)
|
||||
{
|
||||
__uart_data_t *uart_data = port->data;
|
||||
int ret;
|
||||
if (uart_data->frame_ms == 0)
|
||||
{
|
||||
ret = os_pipe_fifo_read(&uart_data->rx_pipe, data, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
__fifo_data_t *fifo_data = os_fifo_take(&uart_data->rx_fifo, 0);
|
||||
if (fifo_data)
|
||||
{
|
||||
ret = size < fifo_data->size ? size : fifo_data->size;
|
||||
if (data)
|
||||
{
|
||||
memcpy(data, fifo_data->data, ret);
|
||||
}
|
||||
os_fifo_free(fifo_data);
|
||||
|
||||
os_scheduler_suspend();
|
||||
uart_data->buffer_used -= ret + sizeof(((__fifo_data_t *)0)->size);
|
||||
os_scheduler_resume();
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
if (ret > 0)
|
||||
{
|
||||
SYS_LOG_DUMP(data, ret, 0, 0);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool _uart_port_is_tart(sb_data_port_t *port)
|
||||
{
|
||||
if (port == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
__uart_data_t *uart_data = port->data;
|
||||
if (uart_data == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (uart_data->frame_ms == 0)
|
||||
{
|
||||
if (!os_pipe_is_valid(&uart_data->rx_pipe))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!os_fifo_q_is_valid(&uart_data->rx_fifo))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint32_t _uart_port_get_rx_length(sb_data_port_t *port)
|
||||
{
|
||||
__uart_data_t *uart_data = port->data;
|
||||
if (uart_data->frame_ms == 0)
|
||||
{
|
||||
return os_pipe_get_valid_size(&uart_data->rx_pipe);
|
||||
}
|
||||
else
|
||||
{
|
||||
__fifo_data_t *fifo_data = os_fifo_peek_head(&uart_data->rx_fifo);
|
||||
if (fifo_data)
|
||||
{
|
||||
return fifo_data->size;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static sb_data_port_vtable_t const s_uart_vtable = {
|
||||
.start = _uart_port_start,
|
||||
.stop = _uart_port_stop,
|
||||
.write = _uart_port_write,
|
||||
.read = _uart_port_read,
|
||||
.is_started = _uart_port_is_tart,
|
||||
.get_rx_length = _uart_port_get_rx_length,
|
||||
};
|
||||
|
||||
int sb_uart_port_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param uart_num 串口号 0..n
|
||||
* @param baudrate 波特率
|
||||
* @param tx_pin TXD 引脚
|
||||
* @param rx_pin RXD 引脚
|
||||
* @param rx_task_priority 内部接收任务的优先级
|
||||
* @param buffer_size 接收缓存大小
|
||||
* @param frame_ms 0: 数据流, > 0: 最少连续有 n 毫秒没有收到数据时成为一帧
|
||||
* @param rx_resume_work 当收到新数据时唤醒的工作项,可设置为 NULL
|
||||
* @return sb_data_port_t*
|
||||
*/
|
||||
sb_data_port_t *sb_uart_port_bind(int uart_num,
|
||||
int baudrate,
|
||||
int tx_pin,
|
||||
int rx_pin,
|
||||
int rx_task_priority,
|
||||
uint16_t buffer_size,
|
||||
uint8_t frame_ms,
|
||||
os_work_t *rx_resume_work)
|
||||
{
|
||||
static sb_data_port_t s_uart_port[_MAX_UART_NUM];
|
||||
static __uart_data_t s_uart_data[_MAX_UART_NUM];
|
||||
|
||||
sb_data_port_t *port = &s_uart_port[uart_num];
|
||||
__uart_data_t *uart_data = &s_uart_data[uart_num];
|
||||
|
||||
SYS_ASSERT(uart_num < _MAX_UART_NUM, "");
|
||||
SYS_ASSERT(port->data == NULL, "The interface has already been bound");
|
||||
|
||||
uart_data->uart_num = uart_num;
|
||||
uart_data->baudrate = baudrate;
|
||||
uart_data->tx_pin = tx_pin;
|
||||
uart_data->rx_pin = rx_pin;
|
||||
uart_data->rx_task_priority = rx_task_priority;
|
||||
uart_data->buffer_size = buffer_size;
|
||||
uart_data->frame_ms = frame_ms;
|
||||
uart_data->rx_resume_work = rx_resume_work;
|
||||
|
||||
port->vtable = &s_uart_vtable;
|
||||
port->data = uart_data;
|
||||
|
||||
return port;
|
||||
}
|
||||
|
||||
void sb_uart_port_unbind(sb_data_port_t *port)
|
||||
{
|
||||
if (_uart_port_is_tart(port))
|
||||
{
|
||||
_uart_port_stop(port);
|
||||
}
|
||||
port->data = NULL;
|
||||
}
|
||||
28
app/drivers/data_port/uart/uart_port.h
Executable file
28
app/drivers/data_port/uart/uart_port.h
Executable file
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* @file uart_port.h
|
||||
* @author LokLiang
|
||||
* @brief
|
||||
* @version 0.1
|
||||
* @date 2023-09-04
|
||||
*
|
||||
* @copyright Copyright (c) 2023
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../sb_data_port.h"
|
||||
#include "os/os.h"
|
||||
|
||||
int sb_uart_port_init(void);
|
||||
|
||||
sb_data_port_t *sb_uart_port_bind(int uartNum,
|
||||
int baudrate,
|
||||
int tx_pin,
|
||||
int rx_pin,
|
||||
int rx_task_priority,
|
||||
uint16_t buffer_size,
|
||||
uint8_t frame_ms,
|
||||
os_work_t *rx_resume_work);
|
||||
|
||||
void sb_uart_port_unbind(sb_data_port_t *port);
|
||||
103
components/system/include/drivers/chip/_hal.h
Executable file
103
components/system/include/drivers/chip/_hal.h
Executable file
@@ -0,0 +1,103 @@
|
||||
#ifndef ___HAL_H__
|
||||
#define ___HAL_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
typedef uint8_t hal_id_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#include "drivers/chip/gpio.h"
|
||||
#include "drivers/chip/clk.h"
|
||||
#include "drivers/chip/irq.h"
|
||||
#include "drivers/chip/uart.h"
|
||||
#include "drivers/chip/i2c.h"
|
||||
#include "drivers/chip/spi.h"
|
||||
#include "drivers/chip/phy.h"
|
||||
#include "drivers/chip/adc.h"
|
||||
#include "drivers/chip/cmp.h"
|
||||
#include "drivers/chip/dac.h"
|
||||
#include "drivers/chip/dma.h"
|
||||
#include "drivers/chip/tim.h"
|
||||
#include "drivers/chip/tick.h"
|
||||
#include "drivers/chip/fmc.h"
|
||||
#include "drivers/chip/wdt.h"
|
||||
#include "drivers/chip/lpm.h"
|
||||
#include "drivers/chip/misc.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t pin;
|
||||
gpio_dir_t dir;
|
||||
gpio_pud_t pull;
|
||||
} hal_pin_hdl_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
hal_pin_hdl_t pin_txd;
|
||||
hal_pin_hdl_t pin_rxd;
|
||||
hal_id_t id;
|
||||
uint8_t irq_prior;
|
||||
uint32_t br;
|
||||
} hal_uart_hdl_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
hal_pin_hdl_t pin_sck;
|
||||
hal_pin_hdl_t pin_sda;
|
||||
hal_id_t id;
|
||||
uint8_t irq_prior;
|
||||
uint32_t freq;
|
||||
} hal_i2c_hdl_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
hal_pin_hdl_t pin_sck;
|
||||
hal_pin_hdl_t pin_mosi;
|
||||
hal_pin_hdl_t pin_miso;
|
||||
hal_id_t id;
|
||||
spi_mode_t mode;
|
||||
uint8_t irq_prior;
|
||||
uint32_t freq;
|
||||
} hal_spi_hdl_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
hal_id_t id;
|
||||
uint16_t vref_mv;
|
||||
uint32_t value_max;
|
||||
uint32_t channel_mask;
|
||||
} hal_adc_hdl_t;
|
||||
|
||||
void drv_hal_init(void);
|
||||
void drv_hal_deinit(void);
|
||||
|
||||
int drv_hal_gpio_pin_init(const hal_pin_hdl_t *gpio_hdl);
|
||||
int drv_hal_uart_init(const hal_uart_hdl_t *uart_hdl);
|
||||
int drv_hal_i2c_init(const hal_i2c_hdl_t *i2c_hdl);
|
||||
int drv_hal_spi_init(const hal_spi_hdl_t *spi_hdl);
|
||||
int drv_hal_drv_adc_init(const hal_adc_hdl_t *adc_hdl);
|
||||
|
||||
void drv_hal_debug_enable(void);
|
||||
void drv_hal_debug_disable(void);
|
||||
|
||||
void drv_hal_sys_reset(void);
|
||||
void drv_hal_sys_exit(int status);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
40
components/system/include/drivers/chip/adc.h
Executable file
40
components/system/include/drivers/chip/adc.h
Executable file
@@ -0,0 +1,40 @@
|
||||
#ifndef __ADC_H__
|
||||
#define __ADC_H__
|
||||
|
||||
#include "drivers/chip/_hal.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
typedef void (*adc_isr_cb_fn)(uint8_t channel_id);
|
||||
|
||||
void drv_adc_pin_configure(hal_id_t id, uint8_t pin);
|
||||
|
||||
void drv_adc_enable(hal_id_t id);
|
||||
void drv_adc_disable(hal_id_t id);
|
||||
|
||||
void drv_adc_init(hal_id_t id, unsigned channel_mask, uint32_t sampling_length);
|
||||
void drv_adc_deinit(hal_id_t id, unsigned channel_mask);
|
||||
|
||||
int drv_adc_irq_callback_enable(hal_id_t id, uint8_t channel_id, adc_isr_cb_fn cb);
|
||||
int drv_adc_irq_callback_disable(hal_id_t id, uint8_t channel_id);
|
||||
|
||||
void drv_adc_irq_enable(hal_id_t id, int priority);
|
||||
void drv_adc_irq_disable(hal_id_t id);
|
||||
|
||||
void drv_adc_start(hal_id_t id, unsigned channel_mask);
|
||||
void drv_adc_stop(hal_id_t id, unsigned channel_mask);
|
||||
|
||||
bool drv_adc_is_busy(hal_id_t id, uint8_t channel_id);
|
||||
bool drv_adc_is_ready(hal_id_t id, uint8_t channel_id);
|
||||
|
||||
int drv_adc_read(hal_id_t id, uint8_t channel_id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
17
components/system/include/drivers/chip/clk.h
Executable file
17
components/system/include/drivers/chip/clk.h
Executable file
@@ -0,0 +1,17 @@
|
||||
#ifndef __CLK_H__
|
||||
#define __CLK_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
unsigned drv_clk_get_cpu_clk(void);
|
||||
|
||||
int drv_clk_calibration(unsigned tar_clk, unsigned cur_clk);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
57
components/system/include/drivers/chip/cmp.h
Executable file
57
components/system/include/drivers/chip/cmp.h
Executable file
@@ -0,0 +1,57 @@
|
||||
#ifndef __HAL_CMP_H__
|
||||
#define __HAL_CMP_H__
|
||||
|
||||
#include "drivers/chip/_hal.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
typedef void (*cmp_isr_cb_fn)(void);
|
||||
|
||||
typedef enum __packed
|
||||
{
|
||||
_CMP_OUTPUT_NONE, // 没有任何输出动作
|
||||
_CMP_OUTPUT_IO, // 输出到 IO
|
||||
_CMP_OUTPUT_EXTI, // 触发 中断线
|
||||
_CMP_OUTPUT_TIM, // 触发 定时器的输入
|
||||
} cmp_output_t;
|
||||
|
||||
typedef enum __packed
|
||||
{
|
||||
_CMP_INT_EDGE_NONE,
|
||||
_CMP_INT_EDGE_FALL,
|
||||
_CMP_INT_EDGE_RISE,
|
||||
_CMP_INT_EDGE_BOTH,
|
||||
} cmp_int_edge_t;
|
||||
|
||||
void drv_cmp_pin_configure_in(hal_id_t id, uint8_t pin);
|
||||
void drv_cmp_pin_configure_out(hal_id_t id, uint8_t pin);
|
||||
|
||||
void drv_cmp_enable(hal_id_t id);
|
||||
void drv_cmp_disable(hal_id_t id);
|
||||
|
||||
void drv_cmp_init(hal_id_t id, cmp_output_t output);
|
||||
void drv_cmp_deinit(hal_id_t id);
|
||||
|
||||
int drv_cmp_get_out_value(hal_id_t id);
|
||||
|
||||
int drv_cmp_irq_callback_enable(hal_id_t id, cmp_isr_cb_fn cb);
|
||||
int drv_cmp_irq_callback_disable(hal_id_t id);
|
||||
|
||||
void drv_cmp_irq_enable(hal_id_t id, cmp_int_edge_t edge, int priority);
|
||||
void drv_cmp_irq_disable(hal_id_t id);
|
||||
|
||||
void drv_cmp_start(hal_id_t id);
|
||||
void drv_cmp_stop(hal_id_t id);
|
||||
|
||||
void drv_cmp_set_cmp_value(hal_id_t id, uint16_t value);
|
||||
|
||||
uint8_t drv_cmp_read(hal_id_t id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
33
components/system/include/drivers/chip/dac.h
Executable file
33
components/system/include/drivers/chip/dac.h
Executable file
@@ -0,0 +1,33 @@
|
||||
#ifndef __DAC_H__
|
||||
#define __DAC_H__
|
||||
|
||||
#include "drivers/chip/_hal.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
typedef void (*dac_isr_cb_fn)(void);
|
||||
|
||||
void drv_dac_pin_configure(hal_id_t id, uint8_t pin);
|
||||
|
||||
void drv_dac_enable(hal_id_t id);
|
||||
void drv_dac_disable(hal_id_t id);
|
||||
|
||||
int drv_dac_init(hal_id_t id, unsigned channel_mask, unsigned bit_width);
|
||||
int drv_dac_deinit(hal_id_t id, unsigned channel_mask);
|
||||
|
||||
int drv_dac_irq_callback_enable(hal_id_t id, dac_isr_cb_fn cb);
|
||||
int drv_dac_irq_callback_disable(hal_id_t id);
|
||||
|
||||
void drv_dac_irq_enable(hal_id_t id, int priority);
|
||||
void drv_dac_irq_disable(hal_id_t id);
|
||||
|
||||
void drv_dac_write(hal_id_t id, unsigned channel_id, int value);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
42
components/system/include/drivers/chip/dma.h
Executable file
42
components/system/include/drivers/chip/dma.h
Executable file
@@ -0,0 +1,42 @@
|
||||
#ifndef __DMA_H__
|
||||
#define __DMA_H__
|
||||
|
||||
#include "drivers/chip/_hal.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
typedef enum __packed
|
||||
{
|
||||
_DMA_DIR_MEM_TO_MEM,
|
||||
_DMA_DIR_PER_TO_MEM,
|
||||
_DMA_DIR_MEM_TO_PER,
|
||||
} dma_dir_t;
|
||||
|
||||
typedef void (*dma_isr_cb_fn)(void);
|
||||
|
||||
void drv_dma_enable(hal_id_t id);
|
||||
void drv_dma_disable(hal_id_t id);
|
||||
|
||||
int drv_dma_init(hal_id_t id, unsigned channel, unsigned prio_level);
|
||||
int drv_dma_deinit(hal_id_t id, unsigned channel);
|
||||
|
||||
int drv_dma_irq_callback_enable(hal_id_t id, unsigned channel, dma_isr_cb_fn cb);
|
||||
int drv_dma_irq_callback_disable(hal_id_t id, unsigned channel);
|
||||
|
||||
void drv_dma_irq_enable(hal_id_t id, unsigned channel, int priority);
|
||||
void drv_dma_irq_disable(hal_id_t id, unsigned channel);
|
||||
|
||||
void drv_dma_set(hal_id_t id, unsigned channel, void *dest, unsigned dest_bit_width, bool dest_inc_mode, const void *src, unsigned src_bit_width, bool src_inc_mode, unsigned count, dma_dir_t dir);
|
||||
void drv_dma_start(hal_id_t id, unsigned channel);
|
||||
void drv_dma_stop(hal_id_t id, unsigned channel);
|
||||
|
||||
unsigned drv_dma_get_remain(hal_id_t id, unsigned channel);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
40
components/system/include/drivers/chip/fmc.h
Executable file
40
components/system/include/drivers/chip/fmc.h
Executable file
@@ -0,0 +1,40 @@
|
||||
#ifndef __FMC_H__
|
||||
#define __FMC_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
void drv_fmc_enable(void);
|
||||
void drv_fmc_disable(void);
|
||||
|
||||
void drv_fmc_lock(void);
|
||||
void drv_fmc_unlock(void);
|
||||
|
||||
unsigned drv_fmc_get_rom_base(void);
|
||||
unsigned drv_fmc_get_rom_size(void);
|
||||
unsigned drv_fmc_get_sector_base(unsigned addr);
|
||||
unsigned drv_fmc_get_sector_size(unsigned addr);
|
||||
|
||||
int drv_fmc_sector_erase(unsigned addr);
|
||||
int drv_fmc_data_write(unsigned addr, const void *src, unsigned size);
|
||||
int drv_fmc_data_read(void *dest, unsigned addr, unsigned size);
|
||||
|
||||
bool drv_fmc_is_busy(void);
|
||||
|
||||
int drv_fmc_set_read_protection(bool enable);
|
||||
int drv_fmc_set_write_protection(bool enable, unsigned start_offset, unsigned size);
|
||||
|
||||
bool drv_fmc_is_read_protection(void);
|
||||
bool drv_fmc_is_write_protection(unsigned addr);
|
||||
|
||||
int drv_fmc_set_wdt(unsigned time_ms);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
60
components/system/include/drivers/chip/gpio.h
Executable file
60
components/system/include/drivers/chip/gpio.h
Executable file
@@ -0,0 +1,60 @@
|
||||
#ifndef __GPIO_H__
|
||||
#define __GPIO_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef __packed
|
||||
#define __packed __attribute__((__packed__))
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
typedef enum __packed
|
||||
{
|
||||
_GPIO_DIR_IN,
|
||||
_GPIO_DIR_ANALOG,
|
||||
_GPIO_DIR_OUT,
|
||||
_GPIO_DIR_OPEN_DRAIN,
|
||||
} gpio_dir_t;
|
||||
|
||||
typedef enum __packed
|
||||
{
|
||||
_GPIO_PUD_NONE,
|
||||
_GPIO_PUD_PULL_UP,
|
||||
_GPIO_PUD_PULL_DOWN,
|
||||
} gpio_pud_t;
|
||||
|
||||
typedef enum __packed
|
||||
{
|
||||
_GPIO_EXTI_EDGE_NONE,
|
||||
_GPIO_EXTI_EDGE_FALL,
|
||||
_GPIO_EXTI_EDGE_RISE,
|
||||
_GPIO_EXTI_EDGE_BOTH,
|
||||
} gpio_exti_edge_t;
|
||||
|
||||
typedef void (*gpio_exti_cb_fn)(void);
|
||||
|
||||
void drv_gpio_enable_all(void);
|
||||
void drv_gpio_disable_all(void);
|
||||
|
||||
int drv_gpio_pin_configure(uint8_t pin, gpio_dir_t dir, gpio_pud_t pull);
|
||||
int drv_gpio_pin_read(uint8_t pin);
|
||||
void drv_gpio_pin_write(uint8_t pin, int value);
|
||||
|
||||
void drv_gpio_exti_callback_enable(gpio_exti_cb_fn cb);
|
||||
void drv_gpio_exti_callback_disable(void);
|
||||
|
||||
void drv_gpio_exti_irq_enable(uint8_t pin, gpio_exti_edge_t polarity, int priority);
|
||||
void drv_gpio_exti_irq_disable(uint8_t pin);
|
||||
|
||||
int drv_gpio_exti_get_pin(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
38
components/system/include/drivers/chip/i2c.h
Executable file
38
components/system/include/drivers/chip/i2c.h
Executable file
@@ -0,0 +1,38 @@
|
||||
#ifndef __I2C_H__
|
||||
#define __I2C_H__
|
||||
|
||||
#include "drivers/chip/_hal.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
typedef void (*i2c_isr_cb_fn)(void);
|
||||
|
||||
void drv_i2c_pin_configure_sck(hal_id_t id, uint8_t pin);
|
||||
void drv_i2c_pin_configure_sda(hal_id_t id, uint8_t pin);
|
||||
|
||||
void drv_i2c_enable(hal_id_t id);
|
||||
void drv_i2c_disable(hal_id_t id);
|
||||
|
||||
void drv_i2c_init(hal_id_t id, uint32_t freq);
|
||||
void drv_i2c_deinit(hal_id_t id);
|
||||
|
||||
int drv_i2c_write(hal_id_t id, char dev_addr, const void *src, unsigned count);
|
||||
int drv_i2c_read(hal_id_t id, void *dest, char dev_addr, unsigned count);
|
||||
|
||||
int drv_i2c_irq_callback_enable(hal_id_t id, i2c_isr_cb_fn cb);
|
||||
int drv_i2c_irq_callback_disable(hal_id_t id);
|
||||
|
||||
void drv_i2c_irq_enable(hal_id_t id, int priority);
|
||||
void drv_i2c_irq_disable(hal_id_t id);
|
||||
|
||||
bool drv_i2c_is_busy(hal_id_t id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
23
components/system/include/drivers/chip/irq.h
Executable file
23
components/system/include/drivers/chip/irq.h
Executable file
@@ -0,0 +1,23 @@
|
||||
#ifndef __IRQ_H__
|
||||
#define __IRQ_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
unsigned drv_irq_disable(void);
|
||||
void drv_irq_enable(unsigned nest);
|
||||
|
||||
unsigned drv_irq_get_nest(void);
|
||||
|
||||
void drv_fiq_disable(void);
|
||||
void drv_fiq_enable(void);
|
||||
|
||||
void drv_irq_hardfault_callback(void ((*cb)(void)));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
19
components/system/include/drivers/chip/lpm.h
Executable file
19
components/system/include/drivers/chip/lpm.h
Executable file
@@ -0,0 +1,19 @@
|
||||
#ifndef __LPM_H__
|
||||
#define __LPM_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
void drv_lpm_wkup_enable(unsigned id);
|
||||
void drv_lpm_wkup_disable(unsigned id);
|
||||
|
||||
void drv_lpm_sleep(void);
|
||||
void drv_lpm_deep_sleep(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
68
components/system/include/drivers/chip/misc.h
Executable file
68
components/system/include/drivers/chip/misc.h
Executable file
@@ -0,0 +1,68 @@
|
||||
#ifndef __MISC_H__
|
||||
#define __MISC_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief 让 CPU 空转延时
|
||||
*
|
||||
* @param us 微秒
|
||||
*/
|
||||
void drv_misc_busy_wait(unsigned us);
|
||||
|
||||
/**
|
||||
* @brief 获取变量的位带映射地址
|
||||
*
|
||||
* @param mem 变量地址
|
||||
* @return 位带映射地址。如无返回 NULL
|
||||
*/
|
||||
unsigned *drv_misc_bitband(void *mem);
|
||||
|
||||
/**
|
||||
* @brief 读取 MCU 身份信息的 MD5 值
|
||||
*
|
||||
* @param out[out] 输出
|
||||
* @retval 0 成功
|
||||
* @retval -1 失败
|
||||
*/
|
||||
int drv_misc_read_id_md5(unsigned char out[16]);
|
||||
|
||||
/**
|
||||
* @brief 设置中断向量地址
|
||||
*
|
||||
* @param vector 中断向量地址
|
||||
*/
|
||||
void drv_misc_set_vector(void *vector);
|
||||
|
||||
/**
|
||||
* @brief 获取中断向量地址
|
||||
*
|
||||
* @return void* 中断向量地址
|
||||
*/
|
||||
void *drv_misc_get_vector(void);
|
||||
|
||||
/**
|
||||
* @brief 根据具体平台,以尽可能快的速度把内存置0
|
||||
*
|
||||
* @param src 内存地址
|
||||
* @param len 内存长度
|
||||
*/
|
||||
void mem_reset(void *src, unsigned len);
|
||||
|
||||
/**
|
||||
* @brief 根据具体平台,以尽可能快的速度复制内存数据
|
||||
*
|
||||
* @param dest[out] 目录内存
|
||||
* @param src 源内存
|
||||
* @param len 长度
|
||||
*/
|
||||
void mem_cpy(void *dest, const void *src, unsigned len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
48
components/system/include/drivers/chip/phy.h
Executable file
48
components/system/include/drivers/chip/phy.h
Executable file
@@ -0,0 +1,48 @@
|
||||
#ifndef __PHY_H__
|
||||
#define __PHY_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/* Defines the PHY link speed. This is align with the speed for MAC. */
|
||||
enum phy_speed
|
||||
{
|
||||
PHY_SPEED_10M = 0U, /* PHY 10M speed. */
|
||||
PHY_SPEED_100M /* PHY 100M speed. */
|
||||
};
|
||||
|
||||
/* Defines the PHY link duplex. */
|
||||
enum phy_duplex
|
||||
{
|
||||
PHY_HALF_DUPLEX = 0U, /* PHY half duplex. */
|
||||
PHY_FULL_DUPLEX /* PHY full duplex. */
|
||||
};
|
||||
|
||||
/*! @brief Defines the PHY loopback mode. */
|
||||
enum phy_loop
|
||||
{
|
||||
PHY_LOCAL_LOOP = 0U, /* PHY local loopback. */
|
||||
PHY_REMOTE_LOOP /* PHY remote loopback. */
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
enum phy_speed speed;
|
||||
enum phy_duplex duplex;
|
||||
enum phy_loop loop;
|
||||
} phy_param_t;
|
||||
|
||||
int drv_phy_init(unsigned phy_addr, unsigned src_clock_hz, phy_param_t *param);
|
||||
int drv_phy_read(unsigned reg, unsigned *data);
|
||||
int drv_phy_write(unsigned reg, unsigned data);
|
||||
int drv_phy_loopback(unsigned mode, unsigned speed, unsigned enable);
|
||||
int drv_phy_get_link_status(unsigned *status);
|
||||
int drv_phy_get_link_speed_duplex(unsigned *speed, unsigned *duplex);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
74
components/system/include/drivers/chip/spi.h
Executable file
74
components/system/include/drivers/chip/spi.h
Executable file
@@ -0,0 +1,74 @@
|
||||
#ifndef __SPI_H__
|
||||
#define __SPI_H__
|
||||
|
||||
#include "drivers/chip/_hal.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
typedef enum __packed
|
||||
{
|
||||
_SPI_MODE_0, // clock polarity is low level and phase is first edge
|
||||
_SPI_MODE_1, // clock polarity is low level and phase is second edge
|
||||
_SPI_MODE_2, // clock polarity is high level and phase is first edge
|
||||
_SPI_MODE_3, // clock polarity is high level and phase is second edge
|
||||
} spi_mode_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bool ms; // false: master, true: slave
|
||||
spi_mode_t mode;
|
||||
bool quad_mode;
|
||||
bool lsb_first;
|
||||
unsigned freq;
|
||||
} spi_init_t;
|
||||
|
||||
typedef void (*spi_isr_cb_fn)(void);
|
||||
|
||||
void drv_spi_pin_configure_nss(hal_id_t id, uint8_t pin);
|
||||
void drv_spi_pin_configure_sck(hal_id_t id, uint8_t pin);
|
||||
void drv_spi_pin_configure_mosi(hal_id_t id, uint8_t pin);
|
||||
void drv_spi_pin_configure_miso(hal_id_t id, uint8_t pin);
|
||||
void drv_spi_pin_configure_io2(hal_id_t id, uint8_t pin);
|
||||
void drv_spi_pin_configure_io3(hal_id_t id, uint8_t pin);
|
||||
|
||||
void drv_spi_enable(hal_id_t id);
|
||||
void drv_spi_disable(hal_id_t id);
|
||||
|
||||
void drv_spi_init(hal_id_t id, const spi_init_t *param);
|
||||
void drv_spi_deinit(hal_id_t id);
|
||||
|
||||
int drv_spi_poll_read(hal_id_t id, void *dest);
|
||||
int drv_spi_poll_write(hal_id_t id, uint8_t data);
|
||||
|
||||
int drv_spi_irq_callback_enable(hal_id_t id, spi_isr_cb_fn cb);
|
||||
int drv_spi_irq_callback_disable(hal_id_t id);
|
||||
|
||||
void drv_spi_irq_enable(hal_id_t id, bool rx, bool tx, int priority);
|
||||
void drv_spi_irq_disable(hal_id_t id, bool rx, bool tx);
|
||||
|
||||
bool drv_spi_is_tx_ready(hal_id_t id);
|
||||
bool drv_spi_is_rx_ready(hal_id_t id);
|
||||
|
||||
void drv_spi_dma_enable(hal_id_t id, bool tx_dma, bool rx_dma, unsigned prio_level);
|
||||
void drv_spi_dma_disable(hal_id_t id, bool tx_dma, bool rx_dma);
|
||||
|
||||
int drv_spi_dma_irq_callback_enable(hal_id_t id, spi_isr_cb_fn cb);
|
||||
int drv_spi_dma_irq_callback_disable(hal_id_t id);
|
||||
|
||||
void drv_spi_dma_irq_enable(hal_id_t id, int priority);
|
||||
void drv_spi_dma_irq_disable(hal_id_t id);
|
||||
|
||||
int drv_spi_dma_set_read(hal_id_t id, void *dest, unsigned len);
|
||||
int drv_spi_dma_set_write(hal_id_t id, const void *src, unsigned len);
|
||||
void drv_spi_dma_start(hal_id_t id);
|
||||
|
||||
bool drv_spi_dma_is_busy(hal_id_t id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
18
components/system/include/drivers/chip/tick.h
Executable file
18
components/system/include/drivers/chip/tick.h
Executable file
@@ -0,0 +1,18 @@
|
||||
#ifndef __TICK_H__
|
||||
#define __TICK_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
void drv_tick_enable(unsigned freq);
|
||||
void drv_tick_disable(void);
|
||||
|
||||
unsigned drv_tick_get_counter(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
136
components/system/include/drivers/chip/tim.h
Executable file
136
components/system/include/drivers/chip/tim.h
Executable file
@@ -0,0 +1,136 @@
|
||||
#ifndef __TIM_H__
|
||||
#define __TIM_H__
|
||||
|
||||
#include "drivers/chip/_hal.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @param channel_id: 0..n
|
||||
* @param channel_mask: 1 << 0, 1 << 1, ... 1 << n
|
||||
*/
|
||||
|
||||
typedef void (*tim_isr_cb_fn)(void);
|
||||
|
||||
/** @defgroup time base
|
||||
* @{
|
||||
*/
|
||||
|
||||
void drv_tim_enable(hal_id_t id);
|
||||
void drv_tim_disable(hal_id_t id);
|
||||
|
||||
void drv_tim_init(hal_id_t id, unsigned period_ns, unsigned reload_enable);
|
||||
void drv_tim_deinit(hal_id_t id);
|
||||
|
||||
int drv_tim_irq_callback_enable(hal_id_t id, tim_isr_cb_fn cb);
|
||||
int drv_tim_irq_callback_disable(hal_id_t id);
|
||||
|
||||
void drv_tim_irq_enable(hal_id_t id, int priority);
|
||||
void drv_tim_irq_disable(hal_id_t id);
|
||||
|
||||
void drv_tim_base_start(hal_id_t id);
|
||||
void drv_tim_base_stop(hal_id_t id);
|
||||
|
||||
unsigned drv_tim_get_period_ns(hal_id_t id);
|
||||
unsigned drv_tim_get_cost_ns(hal_id_t id);
|
||||
unsigned drv_tim_get_remain_ns(hal_id_t id);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup PWM
|
||||
* @{
|
||||
*/
|
||||
|
||||
void drv_pwm_pin_configure(hal_id_t id, uint8_t pin);
|
||||
|
||||
void drv_pwm_enable(hal_id_t id);
|
||||
void drv_pwm_disable(hal_id_t id);
|
||||
|
||||
void drv_pwm_init(hal_id_t id, unsigned period_ns, unsigned reload_enable);
|
||||
void drv_pwm_deinit(hal_id_t id);
|
||||
|
||||
int drv_pwm_irq_callback_enable(hal_id_t id, tim_isr_cb_fn cb);
|
||||
int drv_pwm_irq_callback_disable(hal_id_t id);
|
||||
|
||||
void drv_pwm_irq_enable(hal_id_t id, unsigned channel_mask, int priority);
|
||||
void drv_pwm_irq_disable(hal_id_t id, unsigned channel_mask);
|
||||
|
||||
void drv_pwm_start(hal_id_t id, unsigned channel_mask, unsigned active_level, unsigned pulse_ns);
|
||||
void drv_pwm_stop(hal_id_t id, unsigned channel_mask, unsigned active_level);
|
||||
|
||||
bool drv_pwm_is_busy(hal_id_t id);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup one pluse
|
||||
* @{
|
||||
*/
|
||||
|
||||
void drv_pluse_pin_configure(hal_id_t id, uint8_t pin);
|
||||
|
||||
void drv_pluse_enable(hal_id_t id);
|
||||
void drv_pluse_disable(hal_id_t id);
|
||||
|
||||
void drv_pluse_init(hal_id_t id);
|
||||
void drv_pluse_deinit(hal_id_t id);
|
||||
|
||||
int drv_pluse_irq_callback_enable(hal_id_t id, tim_isr_cb_fn cb);
|
||||
int drv_pluse_irq_callback_disable(hal_id_t id);
|
||||
|
||||
void drv_pluse_irq_enable(hal_id_t id, unsigned channel_mask, int priority);
|
||||
void drv_pluse_irq_disable(hal_id_t id, unsigned channel_mask);
|
||||
|
||||
void drv_pluse_set(hal_id_t id, unsigned channel_mask, unsigned active_level, unsigned period_ns, unsigned pulse_ns);
|
||||
|
||||
bool drv_pluse_is_busy(hal_id_t id, unsigned channel);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup input capture
|
||||
* @{
|
||||
*/
|
||||
|
||||
typedef enum __packed
|
||||
{
|
||||
_IC_EDGE_RISING,
|
||||
_IC_EDGE_FALLING,
|
||||
_IC_EDGE_BOTH,
|
||||
} capture_edge_t;
|
||||
|
||||
void drv_capture_pin_configure(hal_id_t id, uint8_t pin);
|
||||
|
||||
void drv_capture_enable(hal_id_t id);
|
||||
void drv_capture_disable(hal_id_t id);
|
||||
|
||||
void drv_capture_init(hal_id_t id, unsigned channel_mask, capture_edge_t polarity);
|
||||
void drv_capture_deinit(hal_id_t id);
|
||||
|
||||
int drv_capture_irq_callback_enable(hal_id_t id, tim_isr_cb_fn cb);
|
||||
int drv_capture_irq_callback_disable(hal_id_t id);
|
||||
|
||||
void drv_capture_irq_enable(hal_id_t id, unsigned channel_mask, int priority);
|
||||
void drv_capture_irq_disable(hal_id_t id, unsigned channel_mask);
|
||||
|
||||
void drv_capture_start(hal_id_t id, unsigned channel_mask);
|
||||
void drv_capture_stop(hal_id_t id, unsigned channel_mask);
|
||||
|
||||
unsigned drv_capture_get_cap_value(hal_id_t id, uint8_t channel_id);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
56
components/system/include/drivers/chip/uart.h
Executable file
56
components/system/include/drivers/chip/uart.h
Executable file
@@ -0,0 +1,56 @@
|
||||
#ifndef __UART_H__
|
||||
#define __UART_H__
|
||||
|
||||
#include "drivers/chip/_hal.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t br;
|
||||
uint8_t length; /* 7..9 */
|
||||
uint8_t stop_bit; /* 1 or 2 */
|
||||
uint8_t parity; /* 0: none 1: even 2: odd */
|
||||
uint8_t flow_ctrl; /* 0: none 1: RTS 2: CTS 3: RTS+CTS */
|
||||
|
||||
} uart_param_t;
|
||||
|
||||
typedef void (*uart_isr_cb_fn)(void);
|
||||
|
||||
void drv_uart_pin_configure_txd(hal_id_t id, uint8_t pin);
|
||||
void drv_uart_pin_configure_rxd(hal_id_t id, uint8_t pin);
|
||||
|
||||
void drv_uart_enable(hal_id_t id);
|
||||
void drv_uart_disable(hal_id_t id);
|
||||
|
||||
void drv_uart_init(hal_id_t id, const uart_param_t *param);
|
||||
void drv_uart_deinit(hal_id_t id);
|
||||
|
||||
void drv_uart_set_br(hal_id_t id, unsigned clk, unsigned baudrate);
|
||||
unsigned drv_uart_get_br(hal_id_t id, unsigned clk);
|
||||
|
||||
int drv_uart_poll_read(hal_id_t id, void *data);
|
||||
int drv_uart_poll_write(hal_id_t id, uint8_t data);
|
||||
|
||||
int drv_uart_fifo_read(hal_id_t id, void *data, int size);
|
||||
int drv_uart_fifo_fill(hal_id_t id, const void *data, int size);
|
||||
|
||||
int drv_uart_irq_callback_enable(hal_id_t id, uart_isr_cb_fn cb);
|
||||
int drv_uart_irq_callback_disable(hal_id_t id);
|
||||
|
||||
void drv_uart_irq_enable(hal_id_t id, bool rx, bool tx, int priority);
|
||||
void drv_uart_irq_disable(hal_id_t id, bool rx, bool tx);
|
||||
|
||||
bool drv_uart_wait_tx_busy(hal_id_t id);
|
||||
|
||||
bool drv_uart_is_tx_ready(hal_id_t id);
|
||||
bool drv_uart_is_rx_ready(hal_id_t id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
32
components/system/include/drivers/chip/wdt.h
Executable file
32
components/system/include/drivers/chip/wdt.h
Executable file
@@ -0,0 +1,32 @@
|
||||
#ifndef __WDT_H__
|
||||
#define __WDT_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
typedef enum
|
||||
{
|
||||
_WDT_MODE_RESET,
|
||||
_WDT_MODE_INTERRUPT_RESET
|
||||
} wdt_mode_t;
|
||||
|
||||
void wdt_enable(void);
|
||||
void wdt_disable(void);
|
||||
|
||||
void wdt_irq_enable(int priority);
|
||||
void wdt_irq_disable(void);
|
||||
|
||||
void wdt_set_config(wdt_mode_t mode, int int_ms, int reset_ms);
|
||||
|
||||
void wdt_reload(void);
|
||||
unsigned wdt_get_time_cost(void);
|
||||
|
||||
void wdt_clear_int_flag(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
285
components/system/include/list/dlist.h
Executable file
285
components/system/include/list/dlist.h
Executable file
@@ -0,0 +1,285 @@
|
||||
/**
|
||||
* @file dlist.h
|
||||
* @author LokLiang (lokliang@163.com)
|
||||
* @brief
|
||||
* @version 0.1
|
||||
* @date 2023-05-01
|
||||
*
|
||||
* @copyright Copyright (c) 2023
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __DUPLEXLIST_H__
|
||||
#define __DUPLEXLIST_H__
|
||||
|
||||
#include "sys_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#ifndef LIST_NODE_TYPE
|
||||
#define LIST_NODE_TYPE 0 /* 0 -- 使用指针连结(推荐);1 -- 使用偏移量连结,内存的地址允许被迁移并继续管理(推荐) */
|
||||
#endif
|
||||
|
||||
#if LIST_NODE_TYPE == 1
|
||||
typedef int list_node_t;
|
||||
#else
|
||||
typedef void * list_node_t;
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
list_node_t next;
|
||||
list_node_t prev;
|
||||
} dlist_node_t;
|
||||
typedef struct
|
||||
{
|
||||
list_node_t head;
|
||||
} dlist_t;
|
||||
|
||||
__static_inline void dlist_init_list (dlist_t *list);
|
||||
__static_inline void dlist_init_node (dlist_node_t *node);
|
||||
|
||||
__static_inline int dlist_insert_font (dlist_t *list, dlist_node_t *node);
|
||||
__static_inline int dlist_insert_tail (dlist_t *list, dlist_node_t *node);
|
||||
__static_inline int dlist_remove (dlist_t *list, dlist_node_t *node);
|
||||
|
||||
__static_inline int dlist_insert_next (dlist_t *list, dlist_node_t *tar_node, dlist_node_t *new_node);
|
||||
__static_inline int dlist_insert_prev (dlist_t *list, dlist_node_t *tar_node, dlist_node_t *new_node);
|
||||
|
||||
__static_inline void dlist_set_next (dlist_t *list);
|
||||
|
||||
__static_inline dlist_node_t *dlist_take_head (dlist_t *list);
|
||||
__static_inline dlist_node_t *dlist_take_tail (dlist_t *list);
|
||||
|
||||
__static_inline dlist_node_t *dlist_peek_head (dlist_t *list);
|
||||
__static_inline dlist_node_t *dlist_peek_tail (dlist_t *list);
|
||||
|
||||
__static_inline dlist_node_t *dlist_peek_next (dlist_t *list, dlist_node_t *node);
|
||||
__static_inline dlist_node_t *dlist_peek_prev (dlist_t *list, dlist_node_t *node);
|
||||
|
||||
__static_inline dlist_node_t *dlist_peek_next_loop (dlist_t *list, dlist_node_t *node);
|
||||
__static_inline dlist_node_t *dlist_peek_prev_loop (dlist_t *list, dlist_node_t *node);
|
||||
|
||||
__static_inline int dlist_is_pending (dlist_node_t *node);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if LIST_NODE_TYPE == 1
|
||||
#define DLIST_SET(Value1, Value2) (Value1 = Value2 == 0 ? 0 : ((int)Value2 - (int)&Value1) | 1)
|
||||
#define DLIST_GET(Value) ((dlist_node_t*)(Value == 0 ? 0 : ((int)&Value + Value) & ~1))
|
||||
#else
|
||||
#define DLIST_SET(Value1, Value2) (Value1 = (list_node_t)Value2)
|
||||
#define DLIST_GET(Value) ((dlist_node_t*)(Value))
|
||||
#endif
|
||||
|
||||
__static_inline void dlist_init_list(dlist_t *list)
|
||||
{
|
||||
DLIST_SET(list->head, 0);
|
||||
}
|
||||
|
||||
__static_inline void dlist_init_node(dlist_node_t *node)
|
||||
{
|
||||
DLIST_SET(node->next, 0);
|
||||
DLIST_SET(node->prev, 0);
|
||||
}
|
||||
|
||||
__static_inline int dlist_insert_font(dlist_t *list, dlist_node_t *node)
|
||||
{
|
||||
if (dlist_insert_tail(list, node) == 0)
|
||||
{
|
||||
DLIST_SET(list->head, node);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
__static_inline int dlist_insert_tail(dlist_t *list, dlist_node_t *node)
|
||||
{
|
||||
if (DLIST_GET(node->next) != NULL || DLIST_GET(node->prev) != NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
dlist_node_t *first_node = DLIST_GET(list->head);
|
||||
if (first_node == NULL)
|
||||
{
|
||||
/* 直接设置链头 */
|
||||
DLIST_SET(node->next, node);
|
||||
DLIST_SET(node->prev, node);
|
||||
DLIST_SET(list->head, node);
|
||||
}
|
||||
else
|
||||
{
|
||||
dlist_node_t *first_node_prev = DLIST_GET(first_node->prev);
|
||||
|
||||
DLIST_SET(node->next, first_node);
|
||||
DLIST_SET(node->prev, first_node_prev);
|
||||
DLIST_SET(first_node_prev->next, node);
|
||||
DLIST_SET(first_node->prev, node);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
__static_inline int dlist_remove(dlist_t *list, dlist_node_t *node)
|
||||
{
|
||||
if (node == NULL || list == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
dlist_node_t *first_node = DLIST_GET(list->head);
|
||||
dlist_node_t *node_next = DLIST_GET(node->next);
|
||||
if (node_next == NULL || first_node == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (node_next == node) // 是最后一节点
|
||||
{
|
||||
DLIST_SET(list->head, 0);
|
||||
}
|
||||
else // 不是最后一节点
|
||||
{
|
||||
dlist_node_t *node_prev = DLIST_GET(node->prev);
|
||||
if (first_node == node)
|
||||
{
|
||||
DLIST_SET(list->head, node_next); // 链头指向下一节点
|
||||
}
|
||||
DLIST_SET(node_prev->next, node_next);
|
||||
DLIST_SET(node_next->prev, node_prev);
|
||||
}
|
||||
|
||||
DLIST_SET(node->next, 0);
|
||||
DLIST_SET(node->prev, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
__static_inline int dlist_insert_next(dlist_t *list, dlist_node_t *tar_node, dlist_node_t *new_node)
|
||||
{
|
||||
dlist_node_t *tar_node_next = DLIST_GET(tar_node->next);
|
||||
if (DLIST_GET(list->head) == NULL || tar_node_next == NULL || DLIST_GET(new_node->next) != NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
DLIST_SET(new_node->next, tar_node_next);
|
||||
DLIST_SET(new_node->prev, tar_node);
|
||||
DLIST_SET(tar_node_next->prev, new_node);
|
||||
DLIST_SET(tar_node->next, new_node);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
__static_inline int dlist_insert_prev(dlist_t *list, dlist_node_t *tar_node, dlist_node_t *new_node)
|
||||
{
|
||||
dlist_node_t *list_head = DLIST_GET(list->head);
|
||||
if (list_head == NULL || DLIST_GET(tar_node->next) == NULL || DLIST_GET(new_node->next) != NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
DLIST_SET(new_node->next, tar_node);
|
||||
DLIST_SET(new_node->prev, DLIST_GET(tar_node->prev));
|
||||
DLIST_SET(DLIST_GET(tar_node->prev)->next, new_node);
|
||||
DLIST_SET(tar_node->prev, new_node);
|
||||
if (tar_node == list_head) // tar_node 是首个节点
|
||||
{
|
||||
DLIST_SET(list->head, new_node);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
__static_inline void dlist_set_next(dlist_t *list)
|
||||
{
|
||||
if (list != NULL)
|
||||
{
|
||||
dlist_node_t *node = DLIST_GET(list->head);
|
||||
if (node != NULL)
|
||||
{
|
||||
DLIST_SET(list->head, DLIST_GET(node->next)); // 链头指向下一节点
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__static_inline dlist_node_t *dlist_take_head(dlist_t *list)
|
||||
{
|
||||
dlist_node_t *ret = DLIST_GET(list->head);
|
||||
dlist_remove(list, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
__static_inline dlist_node_t *dlist_take_tail(dlist_t *list)
|
||||
{
|
||||
dlist_node_t *ret = dlist_peek_tail(list);
|
||||
dlist_remove(list, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
__static_inline dlist_node_t *dlist_peek_head(dlist_t *list)
|
||||
{
|
||||
return DLIST_GET(list->head);
|
||||
}
|
||||
|
||||
__static_inline dlist_node_t *dlist_peek_tail(dlist_t *list)
|
||||
{
|
||||
dlist_node_t *list_head = DLIST_GET(list->head);
|
||||
if (list_head == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
return DLIST_GET(list_head->prev);
|
||||
}
|
||||
}
|
||||
|
||||
__static_inline dlist_node_t *dlist_peek_next(dlist_t *list, dlist_node_t *node)
|
||||
{
|
||||
dlist_node_t *ret = DLIST_GET(node->next);
|
||||
if (dlist_peek_head(list) == ret)
|
||||
{
|
||||
ret = NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
__static_inline dlist_node_t *dlist_peek_prev(dlist_t *list, dlist_node_t *node)
|
||||
{
|
||||
dlist_node_t *ret = DLIST_GET(node->prev);
|
||||
if (dlist_peek_tail(list) == ret)
|
||||
{
|
||||
ret = NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
__static_inline dlist_node_t *dlist_peek_next_loop(dlist_t *list, dlist_node_t *node)
|
||||
{
|
||||
(void)list;
|
||||
return DLIST_GET(node->next);
|
||||
}
|
||||
|
||||
__static_inline dlist_node_t *dlist_peek_prev_loop(dlist_t *list, dlist_node_t *node)
|
||||
{
|
||||
(void)list;
|
||||
return DLIST_GET(node->prev);
|
||||
}
|
||||
|
||||
__static_inline int dlist_is_pending(dlist_node_t *node)
|
||||
{
|
||||
return (DLIST_GET(node->next) != NULL);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
373
components/system/include/list/flist.h
Executable file
373
components/system/include/list/flist.h
Executable file
@@ -0,0 +1,373 @@
|
||||
/**
|
||||
* @file flist.h
|
||||
* @author LokLiang (lokliang@163.com)
|
||||
* @brief
|
||||
* @version 0.1
|
||||
* @date 2023-05-01
|
||||
*
|
||||
* @copyright Copyright (c) 2023
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __FULLLIST_H__
|
||||
#define __FULLLIST_H__
|
||||
|
||||
#include "sys_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#ifndef LIST_NODE_TYPE
|
||||
#define LIST_NODE_TYPE 0 /* 0 -- 使用指针连结(推荐);1 -- 使用偏移量连结,内存的地址允许被迁移并继续管理(推荐) */
|
||||
#endif
|
||||
|
||||
#if LIST_NODE_TYPE == 1
|
||||
typedef int list_node_t;
|
||||
#else
|
||||
typedef void * list_node_t;
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
list_node_t next;
|
||||
list_node_t prev;
|
||||
list_node_t list;
|
||||
} flist_node_t;
|
||||
typedef struct
|
||||
{
|
||||
list_node_t head;
|
||||
} flist_t;
|
||||
|
||||
__static_inline void flist_init_list (flist_t *list);
|
||||
__static_inline void flist_init_node (flist_node_t *node);
|
||||
|
||||
__static_inline int flist_insert_font (flist_t *list, flist_node_t *node);
|
||||
__static_inline int flist_insert_tail (flist_t *list, flist_node_t *node);
|
||||
__static_inline int flist_remove (flist_t *list, flist_node_t *node);
|
||||
|
||||
__static_inline int flist_insert_next (flist_node_t *tar_node, flist_node_t *new_node);
|
||||
__static_inline int flist_insert_prev (flist_node_t *tar_node, flist_node_t *new_node);
|
||||
__static_inline int flist_node_free (flist_node_t *node);
|
||||
|
||||
__static_inline void flist_set_next (flist_t *list);
|
||||
|
||||
__static_inline flist_node_t *flist_take_head (flist_t *list);
|
||||
__static_inline flist_node_t *flist_take_tail (flist_t *list);
|
||||
|
||||
__static_inline flist_node_t *flist_peek_head (flist_t *list);
|
||||
__static_inline flist_node_t *flist_peek_tail (flist_t *list);
|
||||
|
||||
__static_inline flist_t *flist_peek_list (flist_node_t *node);
|
||||
__static_inline flist_node_t *flist_peek_first (flist_node_t *node);
|
||||
__static_inline flist_node_t *flist_peek_next (flist_node_t *node);
|
||||
__static_inline flist_node_t *flist_peek_prev (flist_node_t *node);
|
||||
|
||||
__static_inline flist_node_t *flist_peek_next_loop (flist_node_t *node);
|
||||
__static_inline flist_node_t *flist_peek_prev_loop (flist_node_t *node);
|
||||
|
||||
__static_inline int flist_is_pending (flist_node_t *node);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if LIST_NODE_TYPE == 1
|
||||
#define FLIST_SET(Value1, Value2) (Value1 = Value2 == 0 ? 0 : ((int)Value2 - (int)&Value1) | 1)
|
||||
#define FLIST_GET(Value) ((flist_node_t*)(Value == 0 ? 0 : ((int)&Value + Value) & ~1))
|
||||
#else
|
||||
#define FLIST_SET(Value1, Value2) (Value1 = (list_node_t)Value2)
|
||||
#define FLIST_GET(Value) ((flist_node_t*)(Value))
|
||||
#endif
|
||||
|
||||
__static_inline void flist_init_list(flist_t *list)
|
||||
{
|
||||
FLIST_SET(list->head, 0);
|
||||
}
|
||||
|
||||
__static_inline void flist_init_node(flist_node_t *node)
|
||||
{
|
||||
FLIST_SET(node->list, 0);
|
||||
FLIST_SET(node->next, 0);
|
||||
FLIST_SET(node->prev, 0);
|
||||
}
|
||||
|
||||
__static_inline int flist_insert_font(flist_t *list, flist_node_t *node)
|
||||
{
|
||||
flist_insert_tail(list, node);
|
||||
FLIST_SET(list->head, node);
|
||||
return 0;
|
||||
}
|
||||
|
||||
__static_inline int flist_insert_tail(flist_t *list, flist_node_t *node)
|
||||
{
|
||||
if (FLIST_GET(node->list) != NULL)
|
||||
{
|
||||
flist_node_free(node);
|
||||
}
|
||||
|
||||
FLIST_SET(node->list, list);
|
||||
|
||||
flist_node_t *first_node = FLIST_GET(list->head);
|
||||
if (first_node == NULL)
|
||||
{
|
||||
/* 直接设置链头 */
|
||||
FLIST_SET(node->next, node);
|
||||
FLIST_SET(node->prev, node);
|
||||
FLIST_SET(list->head, node);
|
||||
}
|
||||
else
|
||||
{
|
||||
flist_node_t *first_node_prev = FLIST_GET(first_node->prev);
|
||||
FLIST_SET(node->next, first_node);
|
||||
FLIST_SET(node->prev, first_node_prev);
|
||||
FLIST_SET(first_node_prev->next, node);
|
||||
FLIST_SET(first_node->prev, node);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
__static_inline int flist_remove(flist_t *list, flist_node_t *node)
|
||||
{
|
||||
if (node == NULL || list == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
flist_node_t *first_node = FLIST_GET(list->head);
|
||||
flist_node_t *node_next = FLIST_GET(node->next);
|
||||
if (node_next == NULL || first_node == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (node_next == node) // 是最后一节点
|
||||
{
|
||||
FLIST_SET(list->head, 0);
|
||||
}
|
||||
else // 不是最后一节点
|
||||
{
|
||||
if (first_node == node)
|
||||
{
|
||||
FLIST_SET(list->head, node_next); // 链头指向下一节点
|
||||
}
|
||||
flist_node_t *node_prev = FLIST_GET(node->prev);
|
||||
FLIST_SET(node_prev->next, node_next);
|
||||
FLIST_SET(node_next->prev, node_prev);
|
||||
}
|
||||
|
||||
FLIST_SET(node->list, 0);
|
||||
FLIST_SET(node->next, 0);
|
||||
FLIST_SET(node->prev, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
__static_inline int flist_insert_next(flist_node_t *tar_node, flist_node_t *new_node)
|
||||
{
|
||||
flist_node_t *tar_node_list = FLIST_GET(tar_node->list);
|
||||
if (tar_node_list == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tar_node == new_node)
|
||||
{
|
||||
flist_node_t *src_node_next = FLIST_GET(new_node->next);
|
||||
if (src_node_next != new_node) // 不是最后一节点
|
||||
{
|
||||
flist_t *list = (flist_t *)FLIST_GET(new_node->list);
|
||||
flist_node_t *first_node = FLIST_GET(list->head);
|
||||
if (first_node == new_node)
|
||||
{
|
||||
FLIST_SET(list->head, src_node_next); // 链头指向下一节点
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (FLIST_GET(new_node->list) != NULL)
|
||||
{
|
||||
flist_node_free(new_node);
|
||||
}
|
||||
flist_node_t *tar_node_next = FLIST_GET(tar_node->next);
|
||||
FLIST_SET(new_node->list, tar_node_list);
|
||||
FLIST_SET(new_node->next, tar_node_next);
|
||||
FLIST_SET(new_node->prev, tar_node);
|
||||
FLIST_SET(tar_node_next->prev, new_node);
|
||||
FLIST_SET(tar_node->next, new_node);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
__static_inline int flist_insert_prev(flist_node_t *tar_node, flist_node_t *new_node)
|
||||
{
|
||||
flist_node_t *tar_node_list = FLIST_GET(tar_node->list);
|
||||
if (tar_node_list == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tar_node == new_node)
|
||||
{
|
||||
flist_node_t *src_node_next = FLIST_GET(new_node->next);
|
||||
if (src_node_next != new_node) // 不是最后一节点
|
||||
{
|
||||
flist_t *list = (flist_t *)FLIST_GET(new_node->list);
|
||||
flist_node_t *first_node = (flist_node_t *)FLIST_GET(list->head);
|
||||
if (first_node == new_node)
|
||||
{
|
||||
FLIST_SET(list->head, src_node_next); // 链头指向下一节点
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (FLIST_GET(new_node->list) != NULL)
|
||||
{
|
||||
flist_node_free(new_node);
|
||||
}
|
||||
flist_node_t *tar_node_prev = FLIST_GET(tar_node->prev);
|
||||
FLIST_SET(new_node->list, tar_node_list);
|
||||
FLIST_SET(new_node->next, tar_node);
|
||||
FLIST_SET(new_node->prev, tar_node_prev);
|
||||
FLIST_SET(tar_node_prev->next, new_node);
|
||||
FLIST_SET(tar_node->prev, new_node);
|
||||
flist_t *list = (flist_t *)tar_node_list;
|
||||
if (tar_node == FLIST_GET(list->head)) // tar_node 是首个节点
|
||||
{
|
||||
FLIST_SET(list->head, new_node);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
__static_inline int flist_node_free(flist_node_t *node)
|
||||
{
|
||||
if (node == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return flist_remove((flist_t *)FLIST_GET(node->list), node);
|
||||
}
|
||||
|
||||
__static_inline void flist_set_next(flist_t *list)
|
||||
{
|
||||
if (list != NULL)
|
||||
{
|
||||
flist_node_t *node = FLIST_GET(list->head);
|
||||
if (node != NULL)
|
||||
{
|
||||
FLIST_SET(list->head, FLIST_GET(node->next)); // 链头指向下一节点
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__static_inline flist_node_t *flist_take_head(flist_t *list)
|
||||
{
|
||||
flist_node_t *ret = FLIST_GET(list->head);
|
||||
flist_remove(list, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
__static_inline flist_node_t *flist_take_tail(flist_t *list)
|
||||
{
|
||||
flist_node_t *ret = flist_peek_tail(list);
|
||||
flist_remove(list, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
__static_inline flist_node_t *flist_peek_head(flist_t *list)
|
||||
{
|
||||
return FLIST_GET(list->head);
|
||||
}
|
||||
|
||||
__static_inline flist_node_t *flist_peek_tail(flist_t *list)
|
||||
{
|
||||
flist_node_t *list_head = FLIST_GET(list->head);
|
||||
if (list_head == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FLIST_GET(list_head->prev);
|
||||
}
|
||||
}
|
||||
|
||||
__static_inline flist_t *flist_peek_list(flist_node_t *node)
|
||||
{
|
||||
return (flist_t *)FLIST_GET(node->list);
|
||||
}
|
||||
|
||||
__static_inline flist_node_t *flist_peek_first(flist_node_t *node)
|
||||
{
|
||||
flist_node_t *node_list = FLIST_GET(node->list);
|
||||
if (node_list == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FLIST_GET(((flist_t *)node_list)->head);
|
||||
}
|
||||
}
|
||||
|
||||
__static_inline flist_node_t *flist_peek_next(flist_node_t *node)
|
||||
{
|
||||
flist_t *pFlist = (flist_t *)FLIST_GET(node->list);
|
||||
if (pFlist == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
flist_node_t *ret = FLIST_GET(node->next);
|
||||
if (flist_peek_head(pFlist) == ret)
|
||||
{
|
||||
ret = NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
__static_inline flist_node_t *flist_peek_prev(flist_node_t *node)
|
||||
{
|
||||
flist_t *pFlist = (flist_t *)FLIST_GET(node->list);
|
||||
if (pFlist == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
flist_node_t *ret = FLIST_GET(node->prev);
|
||||
if (flist_peek_tail(pFlist) == ret)
|
||||
{
|
||||
ret = NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
__static_inline flist_node_t *flist_peek_next_loop(flist_node_t *node)
|
||||
{
|
||||
return FLIST_GET(node->next);
|
||||
}
|
||||
|
||||
__static_inline flist_node_t *flist_peek_prev_loop(flist_node_t *node)
|
||||
{
|
||||
return FLIST_GET(node->prev);
|
||||
}
|
||||
|
||||
__static_inline int flist_is_pending(flist_node_t *node)
|
||||
{
|
||||
return (FLIST_GET(node->next) != NULL);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
248
components/system/include/list/pslist.h
Executable file
248
components/system/include/list/pslist.h
Executable file
@@ -0,0 +1,248 @@
|
||||
/**
|
||||
* @file pslist.h
|
||||
* @author LokLiang (lokliang@163.com)
|
||||
* @brief
|
||||
* @version 0.1
|
||||
* @date 2023-05-01
|
||||
*
|
||||
* @copyright Copyright (c) 2023
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __PSLIST_H__
|
||||
#define __PSLIST_H__
|
||||
|
||||
#include "sys_types.h"
|
||||
|
||||
typedef struct _psnode sys_psnode_t;
|
||||
|
||||
typedef struct _pslist sys_pslist_t;
|
||||
|
||||
struct _psnode
|
||||
{
|
||||
sys_psnode_t *const *next;
|
||||
};
|
||||
|
||||
struct _pslist
|
||||
{
|
||||
sys_psnode_t *const *head;
|
||||
sys_psnode_t *const *tail;
|
||||
};
|
||||
|
||||
#define _CONTAINER_OF(PTR, TYPE, MEMBER) ((TYPE *)&((uint8_t *)PTR)[-(int)&((TYPE *)0)->MEMBER])
|
||||
|
||||
#define SYS_PSLIST_FOR_EACH_NODE(__sl, __sn) \
|
||||
for (__sn = sys_pslist_peek_head(__sl); __sn; \
|
||||
__sn = sys_pslist_peek_next(__sn))
|
||||
|
||||
#define SYS_PSLIST_ITERATE_FROM_NODE(__sl, __sn) \
|
||||
for (__sn = __sn ? sys_pslist_peek_next_no_check(__sn) \
|
||||
: sys_pslist_peek_head(__sl); \
|
||||
__sn; \
|
||||
__sn = sys_pslist_peek_next(__sn))
|
||||
|
||||
#define SYS_PSLIST_FOR_EACH_NODE_SAFE(__sl, __sn, __sns) \
|
||||
for (__sn = sys_pslist_peek_head(__sl), \
|
||||
__sns = sys_pslist_peek_next(__sn); \
|
||||
__sn; \
|
||||
__sn = __sns, __sns = sys_pslist_peek_next(__sn))
|
||||
|
||||
#define SYS_PSLIST_CONTAINER(__ln, __cn, __n) \
|
||||
((__ln) ? _CONTAINER_OF((__ln), __typeof__(*(__cn)), __n) : NULL)
|
||||
|
||||
#define SYS_PSLIST_PEEK_HEAD_CONTAINER(__sl, __cn, __n) \
|
||||
SYS_PSLIST_CONTAINER(sys_pslist_peek_head(__sl), __cn, __n)
|
||||
|
||||
#define SYS_PSLIST_PEEK_TAIL_CONTAINER(__sl, __cn, __n) \
|
||||
SYS_PSLIST_CONTAINER(sys_pslist_peek_tail(__sl), __cn, __n)
|
||||
|
||||
#define SYS_PSLIST_PEEK_NEXT_CONTAINER(__cn, __n) \
|
||||
((__cn) ? SYS_PSLIST_CONTAINER(sys_pslist_peek_next(&((__cn)->__n)), \
|
||||
__cn, __n) \
|
||||
: NULL)
|
||||
|
||||
#define SYS_PSLIST_FOR_EACH_CONTAINER(__sl, __cn, __n) \
|
||||
for (__cn = SYS_PSLIST_PEEK_HEAD_CONTAINER(__sl, __cn, __n); \
|
||||
__cn; \
|
||||
__cn = SYS_PSLIST_PEEK_NEXT_CONTAINER(__cn, __n))
|
||||
|
||||
#define SYS_PSLIST_FOR_EACH_CONTAINER_SAFE(__sl, __cn, __cns, __n) \
|
||||
for (__cn = SYS_PSLIST_PEEK_HEAD_CONTAINER(__sl, __cn, __n), \
|
||||
__cns = SYS_PSLIST_PEEK_NEXT_CONTAINER(__cn, __n); \
|
||||
__cn; \
|
||||
__cn = __cns, __cns = SYS_PSLIST_PEEK_NEXT_CONTAINER(__cn, __n))
|
||||
|
||||
__static_inline void sys_pslist_init(sys_pslist_t *list)
|
||||
{
|
||||
list->head = NULL;
|
||||
list->tail = NULL;
|
||||
}
|
||||
|
||||
#define SYS_PSLIST_STATIC_INIT(ptr_to_list) \
|
||||
{ \
|
||||
NULL, NULL \
|
||||
}
|
||||
|
||||
__static_inline bool sys_pslist_is_empty(sys_pslist_t *list)
|
||||
{
|
||||
return (!list->head);
|
||||
}
|
||||
|
||||
__static_inline sys_psnode_t *const *sys_pslist_peek_head(sys_pslist_t *list)
|
||||
{
|
||||
return list->head;
|
||||
}
|
||||
|
||||
__static_inline sys_psnode_t *const *sys_pslist_peek_tail(sys_pslist_t *list)
|
||||
{
|
||||
return list->tail;
|
||||
}
|
||||
|
||||
__static_inline sys_psnode_t *const *sys_pslist_peek_next_no_check(sys_psnode_t *const *node)
|
||||
{
|
||||
return (*node)->next;
|
||||
}
|
||||
|
||||
__static_inline sys_psnode_t *const *sys_pslist_peek_next(sys_psnode_t *const *node)
|
||||
{
|
||||
return node ? sys_pslist_peek_next_no_check(node) : NULL;
|
||||
}
|
||||
|
||||
__static_inline void sys_pslist_prepend(sys_pslist_t *list,
|
||||
sys_psnode_t *const *node)
|
||||
{
|
||||
(*node)->next = list->head;
|
||||
list->head = node;
|
||||
|
||||
if (!list->tail)
|
||||
{
|
||||
list->tail = list->head;
|
||||
}
|
||||
}
|
||||
|
||||
__static_inline void sys_pslist_append(sys_pslist_t *list,
|
||||
sys_psnode_t *const *node)
|
||||
{
|
||||
(*node)->next = NULL;
|
||||
|
||||
if (!list->tail)
|
||||
{
|
||||
list->tail = node;
|
||||
list->head = node;
|
||||
}
|
||||
else
|
||||
{
|
||||
(*(list->tail))->next = node;
|
||||
list->tail = node;
|
||||
}
|
||||
}
|
||||
|
||||
__static_inline void sys_pslist_append_list(sys_pslist_t *list,
|
||||
sys_psnode_t *const *head, sys_psnode_t *const *tail)
|
||||
{
|
||||
if (!list->tail)
|
||||
{
|
||||
list->head = head;
|
||||
list->tail = tail;
|
||||
}
|
||||
else
|
||||
{
|
||||
(*(list->tail))->next = head;
|
||||
list->tail = tail;
|
||||
}
|
||||
}
|
||||
|
||||
__static_inline void sys_pslist_merge_pslist(sys_pslist_t *list,
|
||||
sys_pslist_t *list_to_append)
|
||||
{
|
||||
sys_pslist_append_list(list, list_to_append->head,
|
||||
list_to_append->tail);
|
||||
sys_pslist_init(list_to_append);
|
||||
}
|
||||
|
||||
__static_inline void sys_pslist_insert(sys_pslist_t *list,
|
||||
sys_psnode_t *const *prev,
|
||||
sys_psnode_t *const *node)
|
||||
{
|
||||
if (!prev)
|
||||
{
|
||||
sys_pslist_prepend(list, node);
|
||||
}
|
||||
else if (!(*prev)->next)
|
||||
{
|
||||
sys_pslist_append(list, node);
|
||||
}
|
||||
else
|
||||
{
|
||||
(*node)->next = (*prev)->next;
|
||||
(*prev)->next = node;
|
||||
}
|
||||
}
|
||||
|
||||
__static_inline sys_psnode_t *const *sys_pslist_get_not_empty(sys_pslist_t *list)
|
||||
{
|
||||
sys_psnode_t *const *node = list->head;
|
||||
|
||||
list->head = (*node)->next;
|
||||
if (list->tail == node)
|
||||
{
|
||||
list->tail = list->head;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
__static_inline sys_psnode_t *const *sys_pslist_get(sys_pslist_t *list)
|
||||
{
|
||||
return sys_pslist_is_empty(list) ? NULL : sys_pslist_get_not_empty(list);
|
||||
}
|
||||
|
||||
__static_inline void sys_pslist_remove(sys_pslist_t *list,
|
||||
sys_psnode_t *const *prev_node,
|
||||
sys_psnode_t *const *node)
|
||||
{
|
||||
if (!prev_node)
|
||||
{
|
||||
list->head = (*node)->next;
|
||||
|
||||
/* Was node also the tail? */
|
||||
if (list->tail == node)
|
||||
{
|
||||
list->tail = list->head;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
(*prev_node)->next = (*node)->next;
|
||||
|
||||
/* Was node the tail? */
|
||||
if (list->tail == node)
|
||||
{
|
||||
list->tail = prev_node;
|
||||
}
|
||||
}
|
||||
|
||||
(*node)->next = NULL;
|
||||
}
|
||||
|
||||
__static_inline bool sys_pslist_find_and_remove(sys_pslist_t *list,
|
||||
sys_psnode_t *const *node)
|
||||
{
|
||||
sys_psnode_t *const *prev = NULL;
|
||||
sys_psnode_t *const *test;
|
||||
|
||||
SYS_PSLIST_FOR_EACH_NODE(list, test)
|
||||
{
|
||||
if (test == node)
|
||||
{
|
||||
sys_pslist_remove(list, prev, node);
|
||||
return true;
|
||||
}
|
||||
|
||||
prev = test;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
412
components/system/include/list/slist.h
Executable file
412
components/system/include/list/slist.h
Executable file
@@ -0,0 +1,412 @@
|
||||
/**
|
||||
* @file slist.h
|
||||
* @author LokLiang (lokliang@163.com)
|
||||
* @brief
|
||||
* @version 0.1
|
||||
* @date 2023-05-01
|
||||
*
|
||||
* @copyright Copyright (c) 2023
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SINGLELIST_H__
|
||||
#define __SINGLELIST_H__
|
||||
|
||||
#include "sys_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#ifndef LIST_NODE_TYPE
|
||||
#define LIST_NODE_TYPE 0 /* 0 -- 使用指针连结(推荐);1 -- 使用偏移量连结,内存的地址允许被迁移并继续管理(推荐) */
|
||||
#endif
|
||||
|
||||
#if LIST_NODE_TYPE == 1
|
||||
typedef int list_node_t;
|
||||
#else
|
||||
typedef void * list_node_t;
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
list_node_t next;
|
||||
} slist_node_t;
|
||||
typedef struct
|
||||
{
|
||||
list_node_t head;
|
||||
list_node_t tail;
|
||||
} slist_t;
|
||||
|
||||
__static_inline void slist_init_list (slist_t *list);
|
||||
__static_inline void slist_init_node (slist_node_t *node);
|
||||
|
||||
__static_inline int slist_insert_font (slist_t *list, slist_node_t *node);
|
||||
__static_inline int slist_insert_tail (slist_t *list, slist_node_t *node);
|
||||
__static_inline int slist_remove (slist_t *list, slist_node_t *node);
|
||||
__static_inline int slist_remove_next (slist_t *list, slist_node_t *prev_node, slist_node_t *remove_node);
|
||||
|
||||
__static_inline int slist_insert_next (slist_t *list, slist_node_t *tar_node, slist_node_t *new_node);
|
||||
__static_inline int slist_insert_prev (slist_t *list, slist_node_t *tar_node, slist_node_t *new_node);
|
||||
|
||||
__static_inline slist_node_t *slist_take_head (slist_t *list);
|
||||
__static_inline slist_node_t *slist_take_tail (slist_t *list);
|
||||
|
||||
__static_inline slist_node_t *slist_peek_head (slist_t *list);
|
||||
__static_inline slist_node_t *slist_peek_tail (slist_t *list);
|
||||
|
||||
__static_inline slist_node_t *slist_peek_next (slist_node_t *node);
|
||||
__static_inline slist_node_t *slist_peek_prev (slist_t *list, slist_node_t *node);
|
||||
|
||||
__static_inline slist_node_t *slist_peek_next_loop (slist_t *list, slist_node_t *node);
|
||||
__static_inline slist_node_t *slist_peek_prev_loop (slist_t *list, slist_node_t *node);
|
||||
|
||||
__static_inline int slist_is_pending (slist_node_t *node);
|
||||
|
||||
#define SLIST_CONTAINER_OF(PTR, TYPE, MEMBER) ((TYPE *)&((uint8_t *)PTR)[-(int)&((TYPE *)0)->MEMBER])
|
||||
|
||||
#define SLIST_FOR_EACH_NODE(__sl, __sn) \
|
||||
for (__sn = slist_peek_head(__sl); __sn; \
|
||||
__sn = slist_peek_next(__sn))
|
||||
|
||||
#define SLIST_ITERATE_FROM_NODE(__sl, __sn) \
|
||||
for (__sn = __sn ? slist_peek_next_no_check(__sn) \
|
||||
: slist_peek_head(__sl); \
|
||||
__sn; \
|
||||
__sn = slist_peek_next(__sn))
|
||||
|
||||
#define SLIST_FOR_EACH_NODE_SAFE(__sl, __sn, __sns) \
|
||||
for (__sn = slist_peek_head(__sl), \
|
||||
__sns = slist_peek_next(__sn); \
|
||||
__sn; \
|
||||
__sn = __sns, __sns = slist_peek_next(__sn))
|
||||
|
||||
#define SLIST_CONTAINER(__ln, __cn, __n) \
|
||||
((__ln) ? SLIST_CONTAINER_OF((__ln), __typeof__(*(__cn)), __n) : NULL)
|
||||
|
||||
#define SLIST_PEEK_HEAD_CONTAINER(__sl, __cn, __n) \
|
||||
SLIST_CONTAINER(slist_peek_head(__sl), __cn, __n)
|
||||
|
||||
#define SLIST_PEEK_TAIL_CONTAINER(__sl, __cn, __n) \
|
||||
SLIST_CONTAINER(slist_peek_tail(__sl), __cn, __n)
|
||||
|
||||
#define SLIST_PEEK_NEXT_CONTAINER(__cn, __n) \
|
||||
((__cn) ? SLIST_CONTAINER(slist_peek_next(&((__cn)->__n)), __cn, __n) : NULL)
|
||||
|
||||
#define SLIST_FOR_EACH_CONTAINER(__sl, __cn, __n) \
|
||||
for (__cn = SLIST_PEEK_HEAD_CONTAINER(__sl, __cn, __n); \
|
||||
__cn; \
|
||||
__cn = SLIST_PEEK_NEXT_CONTAINER(__cn, __n))
|
||||
|
||||
#define SLIST_FOR_EACH_CONTAINER_SAFE(__sl, __cn, __cns, __n) \
|
||||
for (__cn = SLIST_PEEK_HEAD_CONTAINER(__sl, __cn, __n), \
|
||||
__cns = SLIST_PEEK_NEXT_CONTAINER(__cn, __n); \
|
||||
__cn; \
|
||||
__cn = __cns, __cns = SLIST_PEEK_NEXT_CONTAINER(__cn, __n))
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if LIST_NODE_TYPE == 1
|
||||
#define SLIST_SET(Value1, Value2) (Value1 = Value2 == 0 ? 0 : ((int)Value2 - (int)&Value1) | 1)
|
||||
#define SLIST_GET(Value) ((slist_node_t*)(Value == 0 ? 0 : ((int)&Value + Value) & ~1))
|
||||
#else
|
||||
#define SLIST_SET(Value1, Value2) (Value1 = (list_node_t)Value2)
|
||||
#define SLIST_GET(Value) ((slist_node_t*)(Value))
|
||||
#endif
|
||||
|
||||
__static_inline void slist_init_list(slist_t *list)
|
||||
{
|
||||
SLIST_SET(list->head, 0);
|
||||
SLIST_SET(list->tail, 0);
|
||||
}
|
||||
__static_inline void slist_init_node(slist_node_t *node)
|
||||
{
|
||||
SLIST_SET(node->next, 0);
|
||||
}
|
||||
__static_inline int slist_insert_font(slist_t *list, slist_node_t *node)
|
||||
{
|
||||
if (SLIST_GET(node->next) != NULL)
|
||||
{
|
||||
// SYS_LOG_WRN("Node is pending");
|
||||
return -1;
|
||||
}
|
||||
|
||||
slist_node_t *head_node = SLIST_GET(list->head);
|
||||
if (head_node)
|
||||
{
|
||||
SLIST_SET(node->next, head_node);
|
||||
}
|
||||
else
|
||||
{
|
||||
SLIST_SET(node->next, node);
|
||||
SLIST_SET(list->tail, node);
|
||||
}
|
||||
SLIST_SET(list->head, node);
|
||||
|
||||
return 0;
|
||||
}
|
||||
__static_inline int slist_insert_tail(slist_t *list, slist_node_t *node)
|
||||
{
|
||||
if (SLIST_GET(node->next) != NULL)
|
||||
{
|
||||
// SYS_LOG_WRN("Node is pending");
|
||||
return -1;
|
||||
}
|
||||
|
||||
SLIST_SET(node->next, node);
|
||||
if (SLIST_GET(list->head) == NULL)
|
||||
{
|
||||
SLIST_SET(list->head, node);
|
||||
}
|
||||
else
|
||||
{
|
||||
slist_node_t *tail_node = (slist_node_t *)SLIST_GET(list->tail);
|
||||
|
||||
SLIST_SET(tail_node->next, node);
|
||||
}
|
||||
SLIST_SET(list->tail, node);
|
||||
|
||||
return 0;
|
||||
}
|
||||
__static_inline int slist_remove(slist_t *list, slist_node_t *node)
|
||||
{
|
||||
if (node == NULL || list == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
slist_node_t *list_head = SLIST_GET(list->head);
|
||||
slist_node_t *node_next = SLIST_GET(node->next);
|
||||
if (node_next == NULL || list_head == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (node == list_head) // node 是首个节点
|
||||
{
|
||||
if (node == SLIST_GET(list->tail)) // node 是最后一个节点
|
||||
{
|
||||
SLIST_SET(list->head, 0);
|
||||
SLIST_SET(list->tail, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
SLIST_SET(list->head, node_next);
|
||||
}
|
||||
}
|
||||
else // node 不是首个节点
|
||||
{
|
||||
slist_node_t *prev_node = slist_peek_prev(list, node);
|
||||
if (prev_node == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (node == SLIST_GET(list->tail)) // node 是最后一个节点
|
||||
{
|
||||
SLIST_SET(list->tail, prev_node);
|
||||
SLIST_SET(prev_node->next, prev_node);
|
||||
}
|
||||
else
|
||||
{
|
||||
SLIST_SET(prev_node->next, node_next);
|
||||
}
|
||||
}
|
||||
|
||||
SLIST_SET(node->next, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
__static_inline int slist_remove_next(slist_t *list, slist_node_t *prev_node, slist_node_t *remove_node)
|
||||
{
|
||||
if (remove_node == NULL || list == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
slist_node_t *list_head = SLIST_GET(list->head);
|
||||
slist_node_t *node_next = SLIST_GET(remove_node->next);
|
||||
if (node_next == NULL || list_head == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (remove_node == list_head) // remove_node 是首个节点
|
||||
{
|
||||
if (remove_node == SLIST_GET(list->tail)) // remove_node 是最后一个节点
|
||||
{
|
||||
SLIST_SET(list->head, 0);
|
||||
SLIST_SET(list->tail, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
SLIST_SET(list->head, node_next);
|
||||
}
|
||||
}
|
||||
else // remove_node 不是首个节点
|
||||
{
|
||||
if (prev_node == NULL)
|
||||
{
|
||||
prev_node = slist_peek_prev(list, remove_node);
|
||||
if (prev_node == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (remove_node == SLIST_GET(list->tail)) // remove_node 是最后一个节点
|
||||
{
|
||||
SLIST_SET(list->tail, prev_node);
|
||||
SLIST_SET(prev_node->next, prev_node);
|
||||
}
|
||||
else
|
||||
{
|
||||
SLIST_SET(prev_node->next, node_next);
|
||||
}
|
||||
}
|
||||
|
||||
SLIST_SET(remove_node->next, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
__static_inline int slist_insert_next(slist_t *list, slist_node_t *tar_node, slist_node_t *new_node)
|
||||
{
|
||||
slist_node_t *tar_node_next = SLIST_GET(tar_node->next);
|
||||
if (SLIST_GET(list->head) == NULL || tar_node_next == NULL || SLIST_GET(new_node->next) != NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tar_node == SLIST_GET(list->tail)) // tar_node 是最后一个节点
|
||||
{
|
||||
SLIST_SET(new_node->next, new_node);
|
||||
SLIST_SET(tar_node->next, new_node);
|
||||
SLIST_SET(list->tail, new_node);
|
||||
}
|
||||
else
|
||||
{
|
||||
SLIST_SET(new_node->next, tar_node_next);
|
||||
SLIST_SET(tar_node->next, new_node);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
__static_inline int slist_insert_prev(slist_t *list, slist_node_t *tar_node, slist_node_t *new_node)
|
||||
{
|
||||
slist_node_t *list_head = SLIST_GET(list->head);
|
||||
if (list_head == NULL || SLIST_GET(tar_node->next) == NULL || SLIST_GET(new_node->next) != NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tar_node == list_head) // tar_node 是首个节点
|
||||
{
|
||||
SLIST_SET(new_node->next, list_head);
|
||||
SLIST_SET(list->head, new_node);
|
||||
}
|
||||
else
|
||||
{
|
||||
slist_node_t *prev_node = slist_peek_prev(list, tar_node);
|
||||
if (prev_node == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
SLIST_SET(new_node->next, tar_node);
|
||||
SLIST_SET(prev_node->next, new_node);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
__static_inline slist_node_t *slist_take_head(slist_t *list)
|
||||
{
|
||||
slist_node_t *ret = SLIST_GET(list->head);
|
||||
slist_remove(list, ret);
|
||||
return ret;
|
||||
}
|
||||
__static_inline slist_node_t *slist_take_tail(slist_t *list)
|
||||
{
|
||||
slist_node_t *ret = SLIST_GET(list->tail);
|
||||
slist_remove(list, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
__static_inline slist_node_t *slist_peek_head(slist_t *list)
|
||||
{
|
||||
return SLIST_GET(list->head);
|
||||
}
|
||||
__static_inline slist_node_t *slist_peek_tail(slist_t *list)
|
||||
{
|
||||
return SLIST_GET(list->tail);
|
||||
}
|
||||
|
||||
__static_inline slist_node_t *slist_peek_next(slist_node_t *node)
|
||||
{
|
||||
slist_node_t *next_node = SLIST_GET(node->next);
|
||||
if (next_node == node)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
return next_node;
|
||||
}
|
||||
}
|
||||
__static_inline slist_node_t *slist_peek_prev(slist_t *list, slist_node_t *node)
|
||||
{
|
||||
slist_node_t *prev_node = NULL;
|
||||
slist_node_t *test_node = SLIST_GET(list->head);
|
||||
while (test_node && test_node != node && prev_node != test_node)
|
||||
{
|
||||
prev_node = test_node;
|
||||
test_node = SLIST_GET(test_node->next);
|
||||
}
|
||||
if (test_node == node)
|
||||
{
|
||||
return prev_node;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
__static_inline slist_node_t *slist_peek_next_loop(slist_t *list, slist_node_t *node)
|
||||
{
|
||||
slist_node_t *next_node = SLIST_GET(node->next);
|
||||
if (next_node == node)
|
||||
{
|
||||
return SLIST_GET(list->head);
|
||||
}
|
||||
else
|
||||
{
|
||||
return next_node;
|
||||
}
|
||||
}
|
||||
__static_inline slist_node_t *slist_peek_prev_loop(slist_t *list, slist_node_t *node)
|
||||
{
|
||||
slist_node_t *prev_node = SLIST_GET(list->tail);
|
||||
slist_node_t *test_node = SLIST_GET(list->head);
|
||||
while (test_node && test_node != node && prev_node != test_node)
|
||||
{
|
||||
prev_node = test_node;
|
||||
test_node = SLIST_GET(test_node->next);
|
||||
}
|
||||
if (test_node == node)
|
||||
{
|
||||
return prev_node;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
__static_inline int slist_is_pending(slist_node_t *node)
|
||||
{
|
||||
return (SLIST_GET(node->next) != NULL);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
24
components/system/include/os/os.h
Executable file
24
components/system/include/os/os.h
Executable file
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* @file os.h
|
||||
* @author LokLiang (lokliang@163.com)
|
||||
* @brief
|
||||
* @version 0.1
|
||||
* @date 2023-05-01
|
||||
*
|
||||
* @copyright Copyright (c) 2023
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __OS_H__
|
||||
#define __OS_H__
|
||||
|
||||
#include "os/os_thread.h"
|
||||
#include "os/os_timer.h"
|
||||
#include "os/os_work.h"
|
||||
#include "os/os_ipc.h"
|
||||
#include "os/os_semaphore.h"
|
||||
#include "os/os_mutex.h"
|
||||
#include "os/os_service.h"
|
||||
#include "os/os_heap.h"
|
||||
|
||||
#endif /* __OS_H__ */
|
||||
68
components/system/include/os/os_common.h
Executable file
68
components/system/include/os/os_common.h
Executable file
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* @file os_common.h
|
||||
* @author LokLiang (lokliang@163.com)
|
||||
* @brief
|
||||
* @version 0.1
|
||||
* @date 2023-05-01
|
||||
*
|
||||
* @copyright Copyright (c) 2023
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __OS_COMMON_H__
|
||||
#define __OS_COMMON_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
OS_PRIORITY_IDLE = 0,
|
||||
OS_PRIORITY_LOWEST = 1,
|
||||
OS_PRIORITY_LOWER = 2,
|
||||
OS_PRIORITY_LOW = 3,
|
||||
OS_PRIORITY_NORMAL = 4,
|
||||
OS_PRIORITY_HIGH = 5,
|
||||
OS_PRIORITY_HIGHER = 6,
|
||||
OS_PRIORITY_HIGHEST = 7
|
||||
} os_priority;
|
||||
|
||||
typedef enum {
|
||||
OS_OK = 0, /* success */
|
||||
OS_FAIL = -1, /* general failure */
|
||||
OS_E_NOMEM = -2, /* out of memory */
|
||||
OS_E_PARAM = -3, /* invalid parameter */
|
||||
OS_E_TIMEOUT = -4, /* operation timeout */
|
||||
OS_E_ISR = -5, /* not allowed in ISR context */
|
||||
} os_state;
|
||||
|
||||
typedef void * os_handle_t;
|
||||
|
||||
typedef size_t os_time_t;
|
||||
|
||||
#define OS_INVALID_HANDLE NULL /* OS invalid handle */
|
||||
#define OS_WAIT_FOREVER 0xffffffffU /* Wait forever timeout value */
|
||||
#define OS_SEMAPHORE_MAX_COUNT 0xffffffffU /* Maximum count value for semaphore */
|
||||
|
||||
#define OS_MSEC_PER_SEC 1000U /* milliseconds per second */
|
||||
#define OS_USEC_PER_MSEC 1000U /* microseconds per millisecond */
|
||||
#define OS_USEC_PER_SEC 1000000U /* microseconds per second */
|
||||
|
||||
#define OS_TICK (OS_USEC_PER_SEC / OS_TICK_RATE) /* microseconds per tick */
|
||||
|
||||
#define OS_SecsToTicks(sec) ((os_time_t)(sec) * OS_TICK_RATE)
|
||||
#define OS_MSecsToTicks(msec) ((os_time_t)(OS_TICK_RATE < OS_MSEC_PER_SEC ? (msec) / (OS_TICK / OS_USEC_PER_MSEC) : (msec) * (OS_USEC_PER_MSEC / OS_TICK)))
|
||||
#define OS_TicksToMSecs(t) ((os_time_t)(OS_TICK_RATE < OS_MSEC_PER_SEC ? (t) * (OS_TICK / OS_USEC_PER_MSEC) : (t) / (OS_USEC_PER_MSEC / OS_TICK)))
|
||||
#define OS_TicksToSecs(t) ((os_time_t)(t) / (OS_USEC_PER_SEC / OS_TICK))
|
||||
|
||||
#define OS_CONTAINER_OF(PTR, TYPE, MEMBER) ((TYPE *)&((uint8_t *)PTR)[-(int)&((TYPE *)0)->MEMBER])
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __OS_COMMON_H__ */
|
||||
33
components/system/include/os/os_heap.h
Executable file
33
components/system/include/os/os_heap.h
Executable file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* @file os_heap.h
|
||||
* @author LokLiang (lokliang@163.com)
|
||||
* @brief
|
||||
* @version 0.1
|
||||
* @date 2023-05-01
|
||||
*
|
||||
* @copyright Copyright (c) 2023
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __OS_HEAP_H__
|
||||
#define __OS_HEAP_H__
|
||||
|
||||
#include "os/os_common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
void *os_malloc(size_t size);
|
||||
void *os_calloc(size_t size);
|
||||
void *os_realloc(void *p, size_t size);
|
||||
void os_free(void *p);
|
||||
|
||||
void os_heap_info(size_t *used_size, size_t *free_size, size_t *max_block_size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __OS_HEAP_H__ */
|
||||
103
components/system/include/os/os_ipc.h
Executable file
103
components/system/include/os/os_ipc.h
Executable file
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* @file os_ipc.h
|
||||
* @author LokLiang (lokliang@163.com)
|
||||
* @brief
|
||||
* @version 0.1
|
||||
* @date 2023-05-01
|
||||
*
|
||||
* @copyright Copyright (c) 2023
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __OS_IPC_H__
|
||||
#define __OS_IPC_H__
|
||||
|
||||
#include "os/os_work.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif /* #ifdef __cplusplus */
|
||||
|
||||
typedef os_handle_t os_fifo_handle_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
os_fifo_handle_t handle;
|
||||
} os_fifo_t;
|
||||
|
||||
os_state os_fifo_q_create(os_fifo_t *fifo_handle);
|
||||
os_state os_fifo_q_delete(os_fifo_t *fifo_handle);
|
||||
os_state os_fifo_q_clr(os_fifo_t *fifo_handle);
|
||||
|
||||
void os_fifo_q_regist(os_fifo_t *fifo_handle, os_work_t *work_handle, int delay_ticks);
|
||||
void os_fifo_q_unregist(os_fifo_t *fifo_handle);
|
||||
|
||||
void *os_fifo_alloc(size_t size);
|
||||
os_state os_fifo_put(os_fifo_t *fifo_handle, void *fifo_data);
|
||||
|
||||
void *os_fifo_take(os_fifo_t *fifo_handle, os_time_t wait_ms);
|
||||
os_state os_fifo_free(void *fifo_data);
|
||||
|
||||
void *os_fifo_peek_head(os_fifo_t *fifo_handle);
|
||||
void *os_fifo_peek_tail(os_fifo_t *fifo_handle);
|
||||
|
||||
bool os_fifo_q_is_valid(os_fifo_t *fifo_handle);
|
||||
|
||||
typedef os_handle_t os_queue_handle_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
os_queue_handle_t handle;
|
||||
} os_queue_t;
|
||||
|
||||
os_state os_queue_create(os_queue_t *queue_handle, size_t queueLen, size_t itemSize);
|
||||
os_state os_queue_delete(os_queue_t *queue_handle);
|
||||
os_state os_queue_clr(os_queue_t *queue_handle);
|
||||
|
||||
void os_queue_regist(os_queue_t *queue_handle, os_work_t *work_handle, int delay_ticks);
|
||||
void os_queue_unregist(os_queue_t *queue_handle);
|
||||
|
||||
os_state os_queue_send(os_queue_t *queue_handle, const void *item, os_time_t wait_ms);
|
||||
os_state os_queue_recv(os_queue_t *queue_handle, void *item, os_time_t wait_ms);
|
||||
|
||||
void *os_queue_peek_head(os_queue_t *queue_handle);
|
||||
void *os_queue_peek_tail(os_queue_t *queue_handle);
|
||||
|
||||
size_t os_queue_get_item_size(os_queue_t *queue_handle);
|
||||
|
||||
bool os_queue_is_valid(os_queue_t *queue_handle);
|
||||
|
||||
typedef os_handle_t os_pipe_handle_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
os_pipe_handle_t handle;
|
||||
} os_pipe_t;
|
||||
|
||||
os_state os_pipe_create(os_pipe_t *pipe_handle, size_t pipe_size);
|
||||
os_state os_pipe_delete(os_pipe_t *pipe_handle);
|
||||
os_state os_pipe_clr(os_pipe_t *pipe_handle);
|
||||
|
||||
void os_pipe_regist(os_pipe_t *pipe_handle, os_work_t *work_handle, int delay_ticks);
|
||||
void os_pipe_unregist(os_pipe_t *pipe_handle);
|
||||
|
||||
size_t os_pipe_poll_write(os_pipe_t *pipe_handle, uint8_t data);
|
||||
size_t os_pipe_fifo_fill(os_pipe_t *pipe_handle, const void *data, size_t size);
|
||||
size_t os_pipe_poll_read(os_pipe_t *pipe_handle, uint8_t *data);
|
||||
size_t os_pipe_fifo_read(os_pipe_t *pipe_handle, void *data, size_t size);
|
||||
|
||||
bool os_pipe_is_ne(os_pipe_t *pipe_handle);
|
||||
size_t os_pipe_get_valid_size(os_pipe_t *pipe_handle);
|
||||
size_t os_pipe_get_empty_size(os_pipe_t *pipe_handle);
|
||||
|
||||
void os_pipe_peek_valid(os_pipe_t *pipe_handle, void **dst_base, size_t *dst_size);
|
||||
void os_pipe_peek_empty(os_pipe_t *pipe_handle, void **dst_base, size_t *dst_size);
|
||||
|
||||
bool os_pipe_is_valid(os_pipe_t *pipe_handle);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif /* #ifdef __cplusplus */
|
||||
|
||||
#endif /* __OS_IPC_H__ */
|
||||
44
components/system/include/os/os_mutex.h
Executable file
44
components/system/include/os/os_mutex.h
Executable file
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* @file os_mutex.h
|
||||
* @author LokLiang (lokliang@163.com)
|
||||
* @brief
|
||||
* @version 0.1
|
||||
* @date 2023-05-01
|
||||
*
|
||||
* @copyright Copyright (c) 2023
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __OS_MUTEX_H__
|
||||
#define __OS_MUTEX_H__
|
||||
|
||||
#include "os/os_common.h"
|
||||
#include "os/os_thread.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
typedef os_handle_t os_mutex_handle_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
os_mutex_handle_t handle;
|
||||
} os_mutex_t;
|
||||
|
||||
os_state os_mutex_create(os_mutex_t *mutex);
|
||||
os_state os_mutex_delete(os_mutex_t *mutex);
|
||||
|
||||
os_state os_mutex_lock(os_mutex_t *mutex, os_time_t wait_ms);
|
||||
os_state os_mutex_unlock(os_mutex_t *mutex);
|
||||
|
||||
os_thread_handle_t os_mutex_get_holder(os_mutex_t *mutex);
|
||||
|
||||
bool os_mutex_is_valid(os_mutex_t *mutex);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __OS_MUTEX_H__ */
|
||||
41
components/system/include/os/os_semaphore.h
Executable file
41
components/system/include/os/os_semaphore.h
Executable file
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* @file os_semaphore.h
|
||||
* @author LokLiang (lokliang@163.com)
|
||||
* @brief
|
||||
* @version 0.1
|
||||
* @date 2023-05-01
|
||||
*
|
||||
* @copyright Copyright (c) 2023
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __OS_SEMAPHORE_H__
|
||||
#define __OS_SEMAPHORE_H__
|
||||
|
||||
#include "os/os_common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
typedef os_handle_t os_sem_handle_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
os_sem_handle_t handle;
|
||||
} os_sem_t;
|
||||
|
||||
os_state os_sem_create(os_sem_t *sem, size_t init_value, size_t max_value);
|
||||
os_state os_sem_delete(os_sem_t *sem);
|
||||
|
||||
os_state os_sem_take(os_sem_t *sem, os_time_t wait_ms);
|
||||
os_state os_sem_release(os_sem_t *sem);
|
||||
|
||||
bool os_sem_is_valid(os_sem_t *sem);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __OS_SEMAPHORE_H__ */
|
||||
56
components/system/include/os/os_service.h
Executable file
56
components/system/include/os/os_service.h
Executable file
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* @file os_service.h
|
||||
* @author LokLiang (lokliang@163.com)
|
||||
* @brief
|
||||
* @version 0.1
|
||||
* @date 2023-05-01
|
||||
*
|
||||
* @copyright Copyright (c) 2023
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __OS_SERVER_H__
|
||||
#define __OS_SERVER_H__
|
||||
|
||||
#include "os/os_common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
int os_start(void *heap_mem, size_t heap_size);
|
||||
|
||||
void os_int_entry(void);
|
||||
void os_int_exit(void);
|
||||
|
||||
bool os_is_isr_context(void);
|
||||
|
||||
void os_interrupt_disable(void);
|
||||
void os_interrupt_enable(void);
|
||||
|
||||
void os_scheduler_suspend(void);
|
||||
void os_scheduler_resume(void);
|
||||
|
||||
bool os_scheduler_is_running(void);
|
||||
|
||||
void os_sys_print_info(void);
|
||||
|
||||
os_time_t os_get_sys_time(void);
|
||||
|
||||
size_t os_get_sys_ticks(void);
|
||||
|
||||
os_time_t os_calc_ticks_to_msec(size_t ticks);
|
||||
size_t os_calc_msec_to_ticks(os_time_t msec);
|
||||
|
||||
size_t os_cpu_usage(void);
|
||||
|
||||
int os_get_err(void);
|
||||
|
||||
void os_set_err(int err);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __OS_SERVER_H__ */
|
||||
68
components/system/include/os/os_thread.h
Executable file
68
components/system/include/os/os_thread.h
Executable file
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* @file os_thread.h
|
||||
* @author LokLiang (lokliang@163.com)
|
||||
* @brief
|
||||
* @version 0.1
|
||||
* @date 2023-05-01
|
||||
*
|
||||
* @copyright Copyright (c) 2023
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __OS_THREAD_H__
|
||||
#define __OS_THREAD_H__
|
||||
|
||||
#include "os/os_common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
typedef os_handle_t os_thread_handle_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
os_thread_handle_t handle;
|
||||
} os_thread_t;
|
||||
|
||||
typedef void (*os_thread_entry_t)(void *);
|
||||
|
||||
os_state os_thread_init(os_thread_t *thread,
|
||||
const char *name,
|
||||
os_thread_entry_t entry,
|
||||
void *arg,
|
||||
void *stack_base,
|
||||
size_t stack_size,
|
||||
os_priority priority);
|
||||
|
||||
os_state os_thread_create(os_thread_t *thread,
|
||||
const char *name,
|
||||
os_thread_entry_t entry,
|
||||
void *arg,
|
||||
size_t stack_size,
|
||||
os_priority priority);
|
||||
|
||||
os_state os_thread_delete(os_thread_t *thread);
|
||||
|
||||
void os_thread_sleep(os_time_t msec);
|
||||
|
||||
void os_thread_yield(void);
|
||||
|
||||
void os_thread_suspend(os_thread_t *thread);
|
||||
|
||||
void os_thread_resume(os_thread_t *thread);
|
||||
|
||||
os_thread_handle_t os_thread_get_self(void);
|
||||
|
||||
const char *os_thread_get_name(os_thread_t *thread);
|
||||
|
||||
size_t os_thread_stack_min(os_thread_t *thread);
|
||||
|
||||
bool os_thread_is_valid(os_thread_t *thread);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __OS_THREAD_H__ */
|
||||
55
components/system/include/os/os_timer.h
Executable file
55
components/system/include/os/os_timer.h
Executable file
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* @file os_timer.h
|
||||
* @author LokLiang (lokliang@163.com)
|
||||
* @brief
|
||||
* @version 0.1
|
||||
* @date 2023-05-01
|
||||
*
|
||||
* @copyright Copyright (c) 2023
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __OS_TIMER_H__
|
||||
#define __OS_TIMER_H__
|
||||
|
||||
#include "os/os_common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
typedef os_handle_t os_timer_handle_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
os_timer_handle_t handle;
|
||||
} os_timer_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
OS_TIMER_ONCE = 0, /* one shot timer */
|
||||
OS_TIMER_PERIODIC = 1 /* periodic timer */
|
||||
} os_timer_type_t;
|
||||
|
||||
typedef void (*os_timer_cb_fn)(void *arg);
|
||||
|
||||
os_state os_timer_create(os_timer_t *timer, os_timer_cb_fn cb, void *arg);
|
||||
|
||||
os_state os_timer_delete(os_timer_t *timer);
|
||||
|
||||
os_state os_timer_set_period(os_timer_t *timer, os_timer_type_t type, os_time_t period_ms);
|
||||
|
||||
os_state os_timer_start(os_timer_t *timer);
|
||||
|
||||
os_state os_timer_stop(os_timer_t *timer);
|
||||
|
||||
bool os_timer_is_pending(os_timer_t *timer);
|
||||
|
||||
bool os_timer_is_valid(os_timer_t *timer);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __OS_TIMER_H__ */
|
||||
71
components/system/include/os/os_work.h
Executable file
71
components/system/include/os/os_work.h
Executable file
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* @file os_work.h
|
||||
* @author LokLiang (lokliang@163.com)
|
||||
* @brief
|
||||
* @version 0.1
|
||||
* @date 2023-05-01
|
||||
*
|
||||
* @copyright Copyright (c) 2023
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __OS_WORK_H__
|
||||
#define __OS_WORK_H__
|
||||
|
||||
#include "os/os_common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif /* #ifdef __cplusplus */
|
||||
|
||||
typedef os_handle_t os_work_q_handle_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
os_work_q_handle_t handle;
|
||||
} os_work_q_t;
|
||||
|
||||
extern os_work_q_t *default_os_work_q_hdl;
|
||||
|
||||
os_state os_work_q_create(os_work_q_t *work_q_handle,
|
||||
const char *name,
|
||||
size_t stack_size,
|
||||
os_priority priority);
|
||||
|
||||
os_state os_work_q_delete(os_work_q_t *work_q_handle);
|
||||
|
||||
bool os_work_q_is_valid(os_work_q_t *work_q_handle);
|
||||
bool os_work_q_delayed_state(os_work_q_t *work_q_handle);
|
||||
bool os_work_q_ready_state(os_work_q_t *work_q_handle);
|
||||
|
||||
typedef os_handle_t os_work_handle_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
os_work_handle_t handle;
|
||||
} os_work_t;
|
||||
|
||||
typedef void (*os_work_fn)(void *arg);
|
||||
|
||||
os_state os_work_create(os_work_t *work_handle, const char *name, os_work_fn work_route, void *arg, uint8_t sub_prior);
|
||||
void os_work_delete(os_work_t *work_handle);
|
||||
|
||||
bool os_work_is_valid(os_work_t *work_handle);
|
||||
bool os_work_is_pending(os_work_t *work_handle);
|
||||
os_time_t os_work_time_remain(os_work_t *work_handle);
|
||||
|
||||
void os_work_submit(os_work_q_t *work_q_handle, os_work_t *work_handle, os_time_t delay_ms);
|
||||
void os_work_resume(os_work_t *work_handle, os_time_t delay_ms);
|
||||
void os_work_suspend(os_work_t *work_handle);
|
||||
|
||||
void os_work_yield(os_time_t ms);
|
||||
void os_work_sleep(os_time_t ms);
|
||||
void os_work_later(os_time_t ms);
|
||||
void os_work_later_until(os_time_t ms);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif /* #ifdef __cplusplus */
|
||||
|
||||
#endif
|
||||
75
components/system/include/sys/features.h
Executable file
75
components/system/include/sys/features.h
Executable file
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* @file features.h
|
||||
* @author
|
||||
* @brief
|
||||
* In order to redefine int32_t to int when compiles using GCC, this file is
|
||||
* added to override <sys/features.h> of GCC.
|
||||
* @version 0.1
|
||||
* @date 2021-12-09
|
||||
*
|
||||
* @copyright Copyright (c) 2021
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _LIBC_SYS_FEATURES_H_
|
||||
#define _LIBC_SYS_FEATURES_H_
|
||||
|
||||
/*
|
||||
* Redefine some macros defined by GCC
|
||||
*/
|
||||
#ifdef __INT32_MAX__
|
||||
#undef __INT32_MAX__
|
||||
#endif
|
||||
#define __INT32_MAX__ 2147483647
|
||||
|
||||
#ifdef __UINT32_MAX__
|
||||
#undef __UINT32_MAX__
|
||||
#endif
|
||||
#define __UINT32_MAX__ 4294967295U
|
||||
|
||||
#ifdef __INT_LEAST32_MAX__
|
||||
#undef __INT_LEAST32_MAX__
|
||||
#endif
|
||||
#define __INT_LEAST32_MAX__ 2147483647
|
||||
|
||||
#ifdef __UINT_LEAST32_MAX__
|
||||
#undef __UINT_LEAST32_MAX__
|
||||
#endif
|
||||
#define __UINT_LEAST32_MAX__ 4294967295U
|
||||
|
||||
#ifdef __INT_LEAST32_TYPE__
|
||||
#undef __INT_LEAST32_TYPE__
|
||||
#endif
|
||||
#define __INT_LEAST32_TYPE__ int
|
||||
|
||||
#ifdef __UINT_LEAST32_TYPE__
|
||||
#undef __UINT_LEAST32_TYPE__
|
||||
#endif
|
||||
#define __UINT_LEAST32_TYPE__ unsigned int
|
||||
|
||||
#ifdef __INT32_C
|
||||
#undef __INT32_C
|
||||
#endif
|
||||
#define __INT32_C(c) c
|
||||
|
||||
#ifdef __UINT32_C
|
||||
#undef __UINT32_C
|
||||
#endif
|
||||
#define __UINT32_C(c) c ## U
|
||||
|
||||
#ifdef __INT32_TYPE__
|
||||
#undef __INT32_TYPE__
|
||||
#endif
|
||||
#define __INT32_TYPE__ int
|
||||
|
||||
#ifdef __UINT32_TYPE__
|
||||
#undef __UINT32_TYPE__
|
||||
#endif
|
||||
#define __UINT32_TYPE__ unsigned int
|
||||
|
||||
/*
|
||||
* Include <sys/features.h> of compiler
|
||||
*/
|
||||
#include_next <sys/features.h>
|
||||
|
||||
#endif /* _LIBC_SYS_FEATURES_H_ */
|
||||
2
components/system/include/sys/reent.h
Normal file
2
components/system/include/sys/reent.h
Normal file
@@ -0,0 +1,2 @@
|
||||
#pragma once
|
||||
#include_next <sys/reent.h>
|
||||
400
components/system/include/sys_init.h
Executable file
400
components/system/include/sys_init.h
Executable file
@@ -0,0 +1,400 @@
|
||||
/**
|
||||
* @file sys_init.h
|
||||
* @author LokLiang (lokliang@163.com)
|
||||
* @brief
|
||||
* @version 0.1
|
||||
* @date 2023-06-01
|
||||
* @date 2023-05-01
|
||||
*
|
||||
* @copyright Copyright (c) 2023
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SYS_INIT_H__
|
||||
#define __SYS_INIT_H__
|
||||
|
||||
#include "sys_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif /* #ifdef __cplusplus */
|
||||
|
||||
/* initialize function -------------------------------------------------------- */
|
||||
|
||||
#define INIT_EXPORT_BOARD(FN) _INIT_EXPORT(FN, 0, 1) // 定义自动初始化函数:非常早期的初始化,此时调度器还未启动
|
||||
#define INIT_EXPORT_PREV(FN) _INIT_EXPORT(FN, 1, 1) // 定义自动初始化函数:主要是用于纯软件的初始化、没有太多依赖的函数
|
||||
#define INIT_EXPORT_DEVICE(FN) _INIT_EXPORT(FN, 2, 1) // 定义自动初始化函数:外设驱动初始化相关,比如网卡设备
|
||||
#define INIT_EXPORT_COMPONENT(FN) _INIT_EXPORT(FN, 3, 1) // 定义自动初始化函数:组件初始化,比如文件系统或者 LWIP
|
||||
#define INIT_EXPORT_ENV(FN) _INIT_EXPORT(FN, 4, 1) // 定义自动初始化函数:系统环境初始化,比如挂载文件系统
|
||||
#define INIT_EXPORT_APP(FN, PRIOR) _INIT_EXPORT(FN, 5, PRIOR) // 定义自动初始化函数:应用初始化,比如 GUI 应用(PRIOR 建议取值为 0 或 10..99)
|
||||
|
||||
/* module define -------------------------------------------------------------- */
|
||||
|
||||
#define OBJ_EXPORT_DEVICE(OBJECT, NAME) _MODULE_EXPORT(OBJECT, NAME, MODULE_TYPE_DEVICE)
|
||||
#define OBJ_EXPORT_COMPONENT(OBJECT, NAME) _MODULE_EXPORT(OBJECT, NAME, MODULE_TYPE_COMPONENT)
|
||||
|
||||
/* module api------------------------------------------------------------------ */
|
||||
|
||||
__static_inline const void *device_binding(const char *name);
|
||||
__static_inline const char *device_name(const void *object);
|
||||
__static_inline const char *device_search(const char *prefix_name, unsigned int num);
|
||||
|
||||
__static_inline const void *component_binding(const char *name);
|
||||
__static_inline const char *component_name(const void *object);
|
||||
__static_inline const char *component_search(const char *prefix_name, unsigned int num);
|
||||
|
||||
/* code ----------------------------------------------------------------------- */
|
||||
|
||||
/** @defgroup initialize function
|
||||
* @{
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int (*fn)(void); // 初始化函数地址
|
||||
const char *fn_name; // debug: 函数关联名
|
||||
const char *file; // debug: 所在文件名
|
||||
uint16_t line; // debug: 所在文件行
|
||||
uint8_t level; // debug: 初始化等级
|
||||
uint8_t prior; // debug: 初始化优先级
|
||||
} sys_init_t;
|
||||
|
||||
/**
|
||||
* @def _INIT_EXPORT
|
||||
*
|
||||
* @brief 用于如下宏:
|
||||
* INIT_EXPORT_BOARD
|
||||
* INIT_EXPORT_PREV
|
||||
* INIT_EXPORT_DEVICE
|
||||
* INIT_EXPORT_COMPONENT
|
||||
* INIT_EXPORT_ENV
|
||||
* INIT_EXPORT_APP
|
||||
* 输出一个 sys_init_t 类型的数据。
|
||||
* 这些数据将被归为 "(.s_sys_init_t.*)" 段中,编译阶段被排序并链接。
|
||||
* 需要将文件 "sys_init.ld" 添加到链接脚本。
|
||||
* 用于自动初始化。
|
||||
*
|
||||
* @param FN 待函数
|
||||
*
|
||||
* @param LEVEL 按功能划分的优先级
|
||||
*
|
||||
* @param PRIOR 同一功能等级中的优先级,0..99,数值越小越优早执行
|
||||
*
|
||||
* 举例:
|
||||
* @verbatim
|
||||
* static int _init_env_template(void)
|
||||
* {
|
||||
* SYS_LOG_INF("done.\r\n");
|
||||
* return 0;
|
||||
* }
|
||||
* INIT_EXPORT_ENV(_init_env_template);
|
||||
*
|
||||
* static int _init_app_template1(void)
|
||||
* {
|
||||
* SYS_LOG_INF("done.\r\n");
|
||||
* return 0;
|
||||
* }
|
||||
* static int _init_app_template2(void)
|
||||
* {
|
||||
* SYS_LOG_INF("done.\r\n");
|
||||
* return 0;
|
||||
* }
|
||||
* INIT_EXPORT_APP(_init_app_template1, 0);
|
||||
* INIT_EXPORT_APP(_init_app_template2, 1);
|
||||
* @endverbatim
|
||||
*/
|
||||
#define _INIT_EXPORT(FN, LEVEL, PRIOR) \
|
||||
__used __section(".s_sys_init_t." #LEVEL "." #PRIOR) static sys_init_t const \
|
||||
__sys_init_##FN = { \
|
||||
.fn = FN, \
|
||||
.fn_name = #FN, \
|
||||
.line = __LINE__, \
|
||||
.file = __FILE__, \
|
||||
.level = LEVEL, \
|
||||
.prior = PRIOR, \
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup initialize module
|
||||
* @{
|
||||
*/
|
||||
|
||||
typedef enum __packed // 定义模块的类型
|
||||
{
|
||||
MODULE_TYPE_DEVICE, // 模块类型为驱动
|
||||
MODULE_TYPE_COMPONENT, // 模块类型为组件
|
||||
// ...
|
||||
} module_type_t;
|
||||
|
||||
typedef struct // 模块数据结构
|
||||
{
|
||||
const char *name; // 模块数据关联名
|
||||
const void *obj; // 模块数据地址
|
||||
module_type_t type; // 模块数据类型
|
||||
uint16_t line; // debug: 所在文件行
|
||||
const char *file; // debug: 所在文件名
|
||||
} module_t;
|
||||
|
||||
/**
|
||||
* @def _MODULE_EXPORT
|
||||
*
|
||||
* @brief 输出一个指定模块数据结构。用于如下宏:
|
||||
* OBJ_EXPORT_DEVICE
|
||||
* OBJ_EXPORT_COMPONENT
|
||||
* 这些数据结构将被归为 ".sys_module_data" 段中,编译阶段被链接。
|
||||
* 需要将文件 "sys_init.ld" 添加到链接脚本。
|
||||
* 使用 sys_module_binding() 可找到模块数据结构。
|
||||
*
|
||||
* @param OBJECT 子对象(符号)
|
||||
*
|
||||
* @param OBJ_NAME 子对象关联名称(字符串)。使用 sys_module_search() 可遍历已有对象关联名称
|
||||
*
|
||||
* @param MODULE_TYPE 模块类型 @ref module_type_t
|
||||
*
|
||||
* 举例:
|
||||
* @verbatim
|
||||
* #include "device_template.h"
|
||||
*
|
||||
* static void _set_data(device_template_t dev, int data);
|
||||
* static int _get_data(device_template_t dev);
|
||||
*
|
||||
* static device_template_config_t config;
|
||||
*
|
||||
* static struct device_template const device = {
|
||||
* .api = {
|
||||
* .set_data = _set_data,
|
||||
* .get_data = _get_data,
|
||||
* },
|
||||
* .config = &config,
|
||||
* };
|
||||
* OBJ_EXPORT_DEVICE(device, "DRV1");
|
||||
*
|
||||
* static void _set_data(device_template_t dev, int data)
|
||||
* {
|
||||
* dev->config->data = data;
|
||||
* }
|
||||
*
|
||||
* static int _get_data(device_template_t dev)
|
||||
* {
|
||||
* return dev->config->data;
|
||||
* }
|
||||
* @endverbatim
|
||||
*
|
||||
*/
|
||||
#define _MODULE_EXPORT(OBJECT, OBJ_NAME, MODULE_TYPE) \
|
||||
__used __section(".sys_module_data.1") static module_t const \
|
||||
__sys_module_##OBJECT = { \
|
||||
.name = OBJ_NAME, \
|
||||
.obj = &OBJECT, \
|
||||
.type = MODULE_TYPE, \
|
||||
.line = __LINE__, \
|
||||
.file = __FILE__, \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 结合类型和名称,精确匹配查找个由 _MODULE_EXPORT 输出的模块对象。
|
||||
*
|
||||
* @param type 由 _MODULE_EXPORT 输出的模块类型
|
||||
* @param name 由 _MODULE_EXPORT 输出的模块名
|
||||
* @return module_t * 由 _MODULE_EXPORT 输出的模块对象
|
||||
*/
|
||||
__static_inline const module_t *sys_module_binding(module_type_t type, const char *name)
|
||||
{
|
||||
if (name)
|
||||
{
|
||||
extern const module_t __sys_module_leader_0;
|
||||
extern const module_t __sys_module_leader_9;
|
||||
const module_t *module = &__sys_module_leader_0;
|
||||
const module_t *end = &__sys_module_leader_9;
|
||||
while (module < end)
|
||||
{
|
||||
if (module->type == type)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; 1; i++)
|
||||
{
|
||||
if (name[i] != module->name[i])
|
||||
break;
|
||||
if (name[i] == '\0')
|
||||
return module;
|
||||
}
|
||||
}
|
||||
module = &module[1];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 结合类型和名称,查找个由 _MODULE_EXPORT 输出的模块对象名。
|
||||
*
|
||||
* @param type 由 _MODULE_EXPORT 输出的模块类型
|
||||
* @param prefix_name 由 _MODULE_EXPORT 输出的模块名的前缀。例如: prefix_name 为 "UART" ,可能查找到 "UART1", "UART2"...
|
||||
* @param num 匹配到 prefix_name 的第几次时返回,范围 0..n
|
||||
* @return const char * 匹配到的第 num 个名称为 prefix_name.* 的完整对象名,这个对象名可用于 sys_module_binding() 的参数。
|
||||
* @return NULL 表示没对象
|
||||
*/
|
||||
__static_inline const char *sys_module_search(module_type_t type, const char *prefix_name, unsigned int num)
|
||||
{
|
||||
if (prefix_name)
|
||||
{
|
||||
extern const module_t __sys_module_leader_0;
|
||||
extern const module_t __sys_module_leader_9;
|
||||
const module_t *module = &__sys_module_leader_0;
|
||||
const module_t *end = &__sys_module_leader_9;
|
||||
unsigned int match = 0;
|
||||
while (module < end)
|
||||
{
|
||||
if (module->type == type)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; 1; i++)
|
||||
{
|
||||
if (prefix_name[i] == '\0')
|
||||
{
|
||||
if (match < num)
|
||||
{
|
||||
match++;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
return module->name;
|
||||
}
|
||||
}
|
||||
if (prefix_name[i] != module->name[i])
|
||||
break;
|
||||
}
|
||||
}
|
||||
module = &module[1];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取已绑定的对象的关联名
|
||||
*
|
||||
* @param object 由 sys_module_binding() 取得的对象
|
||||
* @return const char * 对象的关联名
|
||||
*/
|
||||
__static_inline const char *sys_module_name(const void *object)
|
||||
{
|
||||
if (object)
|
||||
{
|
||||
extern const module_t __sys_module_leader_0;
|
||||
extern const module_t __sys_module_leader_9;
|
||||
const module_t *module = &__sys_module_leader_0;
|
||||
const module_t *end = &__sys_module_leader_9;
|
||||
while (module < end)
|
||||
{
|
||||
if (module->obj == object)
|
||||
{
|
||||
return module->name;
|
||||
}
|
||||
module = &module[1];
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup module
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief 绑定一个由 OBJ_EXPORT_DEVICE 输出的设备对象
|
||||
*
|
||||
* @param name 由 OBJ_EXPORT_DEVICE 输出的设备名
|
||||
* @return const void * 由 OBJ_EXPORT_DEVICE 输出的设备对象
|
||||
*/
|
||||
__static_inline const void *device_binding(const char *name)
|
||||
{
|
||||
const module_t *module = sys_module_binding(MODULE_TYPE_DEVICE, name);
|
||||
if (module)
|
||||
return module->obj;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取已绑定的对象的关联名
|
||||
*
|
||||
* @param object 由 device_binding() 取得的对象
|
||||
* @return const char * 对象的关联名
|
||||
*/
|
||||
__static_inline const char *device_name(const void *object)
|
||||
{
|
||||
return sys_module_name(object);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 查找 device_binding() 可用的模块对象名。
|
||||
*
|
||||
* @param prefix_name 由 _MODULE_EXPORT 输出的模块名的前缀。例如: prefix_name 为 "UART" ,可能查找到 "UART1", "UART2"...
|
||||
* @param num 匹配到 prefix_name 的第几次时返回,范围 0..n
|
||||
* @return const char * 匹配到的第 num 个名称为 prefix_name.* 的完整对象名
|
||||
* @return NULL 表示没对象
|
||||
*/
|
||||
__static_inline const char *device_search(const char *prefix_name, unsigned int num)
|
||||
{
|
||||
return sys_module_search(MODULE_TYPE_DEVICE, prefix_name, num);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 绑定一个由 OBJ_EXPORT_COMPONENT 输出的设备对象
|
||||
*
|
||||
* @param name 由 OBJ_EXPORT_COMPONENT 输出的设备名
|
||||
* @return const void * 由 OBJ_EXPORT_COMPONENT 输出的设备对象
|
||||
*/
|
||||
__static_inline const void *component_binding(const char *name)
|
||||
{
|
||||
const module_t *module = sys_module_binding(MODULE_TYPE_COMPONENT, name);
|
||||
if (module)
|
||||
return module->obj;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 获取已绑定的对象的关联名
|
||||
*
|
||||
* @param object 由 component_binding() 取得的对象
|
||||
* @return const char * 对象的关联名
|
||||
*/
|
||||
__static_inline const char *component_name(const void *object)
|
||||
{
|
||||
return sys_module_name(object);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 查找 component_binding() 可用的模块对象名。
|
||||
*
|
||||
* @param prefix_name 由 _MODULE_EXPORT 输出的模块名的前缀。例如: prefix_name 为 "UART" ,可能查找到 "UART1", "UART2"...
|
||||
* @param num 匹配到 prefix_name 的第几次时返回,范围 0..n
|
||||
* @return const char * 匹配到的第 num 个名称为 prefix_name.* 的完整对象名
|
||||
* @return NULL 表示没对象
|
||||
*/
|
||||
__static_inline const char *component_search(const char *prefix_name, unsigned int num)
|
||||
{
|
||||
return sys_module_search(MODULE_TYPE_COMPONENT, prefix_name, num);
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif /* #ifdef __cplusplus */
|
||||
|
||||
#endif
|
||||
436
components/system/include/sys_log.h
Executable file
436
components/system/include/sys_log.h
Executable file
@@ -0,0 +1,436 @@
|
||||
/**
|
||||
* @file sys_log.h
|
||||
* @author LokLiang (lokliang@163.com)
|
||||
* @brief
|
||||
* @version 0.1
|
||||
* @date 2023-05-01
|
||||
*
|
||||
* @copyright Copyright (c) 2023
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SYS_LOG_H__
|
||||
#define __SYS_LOG_H__
|
||||
|
||||
#include "sys_types.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#ifndef SYS_LOG_DOMAIN
|
||||
#define SYS_LOG_DOMAIN "general"
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SYS_LOG_LEVEL
|
||||
#define CONFIG_SYS_LOG_LEVEL SYS_LOG_LEVEL_INF /* 配置日志打印的等级 */
|
||||
#endif
|
||||
|
||||
#define SYS_LOG_LEVEL_OFF 0
|
||||
#define SYS_LOG_LEVEL_ERR 1
|
||||
#define SYS_LOG_LEVEL_WRN 2
|
||||
#define SYS_LOG_LEVEL_INF 3
|
||||
#define SYS_LOG_LEVEL_DBG 4
|
||||
|
||||
#ifndef CONFIG_SYS_LOG_COLOR_ON
|
||||
#define CONFIG_SYS_LOG_COLOR_ON 1 /* 使能打印颜色 */
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SYS_LOG_LOCAL_ON
|
||||
#define CONFIG_SYS_LOG_LOCAL_ON 1 /* 强制使能打印所在文件位置 */
|
||||
#endif
|
||||
|
||||
#define SYS_PRINT printf
|
||||
#define SYS_VPRINT vprintf
|
||||
#define SYS_SPRINT sprintf
|
||||
#define SYS_SNPRINT snprintf
|
||||
#define SYS_VSNPRINT vsnprintf
|
||||
|
||||
#ifndef CONFIG_SYS_LOG_CONS_ON
|
||||
#define CONFIG_SYS_LOG_CONS_ON (CONFIG_SYS_LOG_LEVEL > SYS_LOG_LEVEL_OFF) /* 打印控制总开关 */
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SYS_LOG_DUMP_ON
|
||||
#define CONFIG_SYS_LOG_DUMP_ON CONFIG_SYS_LOG_DBG_ON /* 使能打印二进制和十六进制类型 */
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SYS_LOG_DBG_ON
|
||||
#define CONFIG_SYS_LOG_DBG_ON (CONFIG_SYS_LOG_LEVEL >= SYS_LOG_LEVEL_DBG) /* 使能打印调试类型*/
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SYS_LOG_INF_ON
|
||||
#define CONFIG_SYS_LOG_INF_ON (CONFIG_SYS_LOG_LEVEL >= SYS_LOG_LEVEL_INF) /* 使能打印信息类型 */
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SYS_LOG_WRN_ON
|
||||
#define CONFIG_SYS_LOG_WRN_ON (CONFIG_SYS_LOG_LEVEL >= SYS_LOG_LEVEL_WRN) /* 使能打印警告类型 */
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SYS_LOG_ERR_ON
|
||||
#define CONFIG_SYS_LOG_ERR_ON (CONFIG_SYS_LOG_LEVEL >= SYS_LOG_LEVEL_ERR) /* 使能打印错误类型 */
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SYS_LOG_ASS_ON
|
||||
#define CONFIG_SYS_LOG_ASS_ON (CONFIG_SYS_LOG_LEVEL >= SYS_LOG_LEVEL_INF) /* 使能有效性检测 */
|
||||
#endif
|
||||
|
||||
#define CONS_PRINT(FMT, ...) \
|
||||
do \
|
||||
{ \
|
||||
if (CONFIG_SYS_LOG_CONS_ON) \
|
||||
{ \
|
||||
SYS_PRINT(FMT, ##__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#ifndef CONS_ABORT
|
||||
#define CONS_ABORT() \
|
||||
do \
|
||||
{ \
|
||||
volatile int FLAG = 0; \
|
||||
do \
|
||||
{ \
|
||||
} while (FLAG == 0); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#if (CONFIG_SYS_LOG_COLOR_ON == 1)
|
||||
#define _COLOR_R "\033[31m" /* 红 RED */
|
||||
#define _COLOR_G "\033[32m" /* 绿 GREEN */
|
||||
#define _COLOR_Y "\033[33m" /* 黄 YELLOW */
|
||||
#define _COLOR_B "\033[34m" /* 蓝 BLUE */
|
||||
#define _COLOR_P "\033[35m" /* 紫 PURPLE */
|
||||
#define _COLOR_C "\033[36m" /* 青 CYAN */
|
||||
#define _COLOR_RY "\033[41;33m" /* 红底黄字 */
|
||||
#define _COLOR_END "\033[0m" /* 结束 */
|
||||
#else
|
||||
#define _COLOR_R "" /* 红 */
|
||||
#define _COLOR_G "" /* 绿 */
|
||||
#define _COLOR_Y "" /* 黄 */
|
||||
#define _COLOR_B "" /* 蓝 */
|
||||
#define _COLOR_P "" /* 紫 */
|
||||
#define _COLOR_C "" /* 青 */
|
||||
#define _COLOR_RY "" /* 红底黄字 */
|
||||
#define _COLOR_END "" /* 结束 */
|
||||
#endif
|
||||
|
||||
#define _DO_SYS_LOG(FLAG, FMT, ARG...) \
|
||||
do \
|
||||
{ \
|
||||
if (FLAG) \
|
||||
{ \
|
||||
CONS_PRINT(FMT, ##ARG); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define _FILENAME(FILE) (strrchr(FILE, '/') ? (strrchr(FILE, '/') + 1) : (strrchr(FILE, '\\') ? (strrchr(FILE, '\\') + 1) : FILE))
|
||||
|
||||
#define _GEN_DOMAIN "[" SYS_LOG_DOMAIN "] "
|
||||
|
||||
#define _SYS_LOG(FLAG, INFO, FMT, ...) _DO_SYS_LOG(FLAG, INFO "%s:%u \t%s =>\t" FMT "\r\n", \
|
||||
_FILENAME(__FILE__), __LINE__, __FUNCTION__, ##__VA_ARGS__)
|
||||
|
||||
#if (CONFIG_SYS_LOG_LOCAL_ON == 1 || CONFIG_SYS_LOG_DBG_ON == 1)
|
||||
#define _SYS_LOG_COLOR(FLAG, INFO, COLOR, FMT, ...) _DO_SYS_LOG(FLAG, INFO "%s:%u \t%s =>\t" COLOR FMT _COLOR_END "\r\n", \
|
||||
_FILENAME(__FILE__), __LINE__, __FUNCTION__, ##__VA_ARGS__)
|
||||
#else
|
||||
#define _SYS_LOG_COLOR(FLAG, INFO, COLOR, FMT, ...) _DO_SYS_LOG(FLAG, INFO "%s =>\t" COLOR FMT _COLOR_END "\r\n", \
|
||||
__FUNCTION__, ##__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#define SYS_LOG_DBG(FMT, ...) _SYS_LOG(CONFIG_SYS_LOG_DBG_ON, "[DBG] " _GEN_DOMAIN, FMT, ##__VA_ARGS__)
|
||||
#define SYS_LOG_INF(FMT, ...) _SYS_LOG_COLOR(CONFIG_SYS_LOG_INF_ON, "[INF] | " _GEN_DOMAIN, _COLOR_G, FMT, ##__VA_ARGS__)
|
||||
#define SYS_LOG_WRN(FMT, ...) _SYS_LOG_COLOR(CONFIG_SYS_LOG_WRN_ON, "[WRN] * " _GEN_DOMAIN, _COLOR_Y, FMT, ##__VA_ARGS__)
|
||||
#define SYS_LOG_ERR(FMT, ...) \
|
||||
do \
|
||||
{ \
|
||||
if (CONFIG_SYS_LOG_ERR_ON) \
|
||||
{ \
|
||||
_SYS_LOG_COLOR(1, "[ERR] - " _GEN_DOMAIN, _COLOR_R, FMT, ##__VA_ARGS__); \
|
||||
CONS_ABORT(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define SYS_LOG(FMT, ...) \
|
||||
do \
|
||||
{ \
|
||||
if (CONFIG_SYS_LOG_CONS_ON) \
|
||||
{ \
|
||||
CONS_PRINT(_GEN_DOMAIN "- %s:%u, %s =>\t" _COLOR_B FMT _COLOR_END "\r\n", \
|
||||
_FILENAME(__FILE__), __LINE__, __FUNCTION__, ##__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define SYS_ASSERT_FALSE(EXP, FMT, ...) \
|
||||
do \
|
||||
{ \
|
||||
if (CONFIG_SYS_LOG_ASS_ON && (EXP)) \
|
||||
{ \
|
||||
CONS_PRINT("[ASS] # " _GEN_DOMAIN "%s:%u \t%s =>\t" _COLOR_RY "%s" _COLOR_END "; ## " FMT "\r\n", \
|
||||
_FILENAME(__FILE__), __LINE__, __FUNCTION__, #EXP, ##__VA_ARGS__); \
|
||||
CONS_ABORT(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define SYS_ASSERT(EXP, FMT, ...) \
|
||||
do \
|
||||
{ \
|
||||
if (CONFIG_SYS_LOG_ASS_ON && !(EXP)) \
|
||||
{ \
|
||||
CONS_PRINT("[ASS] # " _GEN_DOMAIN "%s:%u \t%s =>\t" _COLOR_RY "!(%s)" _COLOR_END "; ## " FMT "\r\n", \
|
||||
_FILENAME(__FILE__), __LINE__, __FUNCTION__, #EXP, ##__VA_ARGS__); \
|
||||
CONS_ABORT(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* @brief Print data in hexadecima
|
||||
*
|
||||
* @param P point to data base
|
||||
* @param SIZE data size (bytes)
|
||||
* @param ALIGN word length, 1, 2, 4, 8
|
||||
* @param ENDIAN 0 -- little-endian, 1 -- big-endian
|
||||
*/
|
||||
#define SYS_LOG_DUMP(P, SIZE, ALIGN, ENDIAN) \
|
||||
do \
|
||||
{ \
|
||||
if (CONFIG_SYS_LOG_CONS_ON && CONFIG_SYS_LOG_DUMP_ON) \
|
||||
{ \
|
||||
_SYS_LOG_COLOR(1, "[HEX]: " _GEN_DOMAIN, _COLOR_C, #P ": %d bytes%s", \
|
||||
SIZE, \
|
||||
ALIGN <= 1 ? "" : ENDIAN ? ", big-endian" \
|
||||
: ", little-endian"); \
|
||||
_sys_log_dump((unsigned)P, P, SIZE, ALIGN, ENDIAN); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* @brief Print data in binary
|
||||
*
|
||||
* @param P point to data base
|
||||
* @param SIZE data size (bytes)
|
||||
* @param ALIGN word length, 1, 2, 4, 8
|
||||
* @param ENDIAN 0 -- little-endian, 1 -- big-endian
|
||||
*/
|
||||
#define SYS_LOG_BIN(P, SIZE, ALIGN, ENDIAN) \
|
||||
do \
|
||||
{ \
|
||||
if (CONFIG_SYS_LOG_CONS_ON && CONFIG_SYS_LOG_DUMP_ON) \
|
||||
{ \
|
||||
_SYS_LOG_COLOR(1, "[BIN]: " _GEN_DOMAIN, _COLOR_C, #P ": %d bytes%s", \
|
||||
SIZE, \
|
||||
ALIGN <= 1 ? "" : ENDIAN ? ", big-endian" \
|
||||
: ", little-endian"); \
|
||||
_sys_log_bin((unsigned)P, P, SIZE, ALIGN, ENDIAN); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
__static_inline void _sys_log_dump(unsigned addr,
|
||||
const void *p,
|
||||
int size,
|
||||
int width,
|
||||
int endian)
|
||||
{
|
||||
#define BYTES_PRE_LINE 16
|
||||
if (size)
|
||||
{
|
||||
int i, ii, j;
|
||||
char buf[4 + 4 * BYTES_PRE_LINE];
|
||||
char *ascii;
|
||||
int len1;
|
||||
int len2;
|
||||
int lenmax;
|
||||
width = (width <= 1 ? 1 : (width <= 2 ? 2 : (width <= 4 ? 4 : 8)));
|
||||
size = (size + width - 1) / width;
|
||||
len1 = (1 + width * 2) * ((BYTES_PRE_LINE + width - 1) / width) - 1;
|
||||
len2 = 3 + (BYTES_PRE_LINE + width - 1) / width * width;
|
||||
lenmax = len1 + len2;
|
||||
ascii = &buf[len1 + 2];
|
||||
for (i = 0; i < 6 + sizeof(void *) * 2; i++)
|
||||
{
|
||||
SYS_PRINT("-");
|
||||
}
|
||||
for (i = 0; i < lenmax; i++)
|
||||
{
|
||||
buf[i] = '-';
|
||||
}
|
||||
buf[i] = '\0';
|
||||
SYS_PRINT("%s\r\n", buf);
|
||||
ii = (BYTES_PRE_LINE + width - 1) / width;
|
||||
while (size)
|
||||
{
|
||||
int index1 = 0;
|
||||
int index2 = 0;
|
||||
SYS_PRINT(_COLOR_Y "[" _COLOR_END "0x%08X" _COLOR_Y "]" _COLOR_END ": ", (unsigned)addr);
|
||||
for (i = 0; i < ii;)
|
||||
{
|
||||
for (j = 0; j < width; j++)
|
||||
{
|
||||
if (endian)
|
||||
{
|
||||
index1 += SYS_SPRINT(&buf[index1], "%02x", ((uint8_t *)p)[j]);
|
||||
}
|
||||
else
|
||||
{
|
||||
index1 += SYS_SPRINT(&buf[index1], "%02x", ((uint8_t *)p)[width - j - 1]);
|
||||
}
|
||||
if (((uint8_t *)p)[j] >= ' ' && ((uint8_t *)p)[j] < 0x7f)
|
||||
{
|
||||
index2 += SYS_SPRINT(&ascii[index2], "%c", ((uint8_t *)p)[j]);
|
||||
}
|
||||
else
|
||||
{
|
||||
index2 += SYS_SPRINT(&ascii[index2], ".");
|
||||
}
|
||||
}
|
||||
addr += width;
|
||||
p = &((uint8_t *)p)[width];
|
||||
if (--size > 0 && ++i < ii)
|
||||
{
|
||||
index1 += SYS_SPRINT(&buf[index1], " ");
|
||||
}
|
||||
else
|
||||
{
|
||||
while (index1 < len1)
|
||||
{
|
||||
buf[index1++] = ' ';
|
||||
}
|
||||
buf[index1++] = ' ';
|
||||
buf[index1++] = '|';
|
||||
index1 += index2;
|
||||
while (index1 < lenmax - 1)
|
||||
{
|
||||
buf[index1++] = ' ';
|
||||
}
|
||||
buf[index1++] = '\0';
|
||||
SYS_PRINT("%s|\r\n", buf);
|
||||
}
|
||||
if (size == 0)
|
||||
{
|
||||
for (i = 0; i < 6 + sizeof(void *) * 2; i++)
|
||||
{
|
||||
SYS_PRINT("=");
|
||||
}
|
||||
for (i = 0; i < lenmax; i++)
|
||||
{
|
||||
buf[i] = '=';
|
||||
}
|
||||
buf[i] = '\0';
|
||||
SYS_PRINT("%s\r\n", buf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#undef BYTES_PRE_LINE
|
||||
}
|
||||
|
||||
__static_inline void _sys_log_bin(unsigned addr,
|
||||
const void *p,
|
||||
int size,
|
||||
int width,
|
||||
int endian)
|
||||
{
|
||||
#define BITS_PRE_LINE 64
|
||||
if (size)
|
||||
{
|
||||
uint8_t value[8];
|
||||
int i, j;
|
||||
int lenmax;
|
||||
width = (width <= 1 ? 1 : (width <= 2 ? 2 : (width <= 4 ? 4 : 8)));
|
||||
width = width < BITS_PRE_LINE ? width : BITS_PRE_LINE;
|
||||
size = (size + width - 1) / width * width;
|
||||
lenmax = (1 + 3 * 8) * width;
|
||||
for (i = 0; i < 9 + sizeof(void *) * 2 + width * 2 + width * 8 / 4 + lenmax; i++)
|
||||
{
|
||||
SYS_PRINT("-");
|
||||
}
|
||||
SYS_PRINT("\r\n");
|
||||
for (i = 0; i < 8 + sizeof(void *) * 2 + width * 2; i++)
|
||||
{
|
||||
SYS_PRINT(" ");
|
||||
}
|
||||
for (i = 0; i < 8 * width; i++)
|
||||
{
|
||||
if (i % 4 == 0)
|
||||
{
|
||||
if (i % 8 == 0)
|
||||
{
|
||||
SYS_PRINT(" ");
|
||||
}
|
||||
SYS_PRINT(" ");
|
||||
}
|
||||
SYS_PRINT("%3d", 8 * width - 1 - i);
|
||||
}
|
||||
SYS_PRINT("\r\n");
|
||||
for (i = 0; i < 9 + sizeof(void *) * 2 + width * 2 + width * 8 / 4 + lenmax; i++)
|
||||
{
|
||||
SYS_PRINT("~");
|
||||
}
|
||||
SYS_PRINT("\r\n");
|
||||
while (size)
|
||||
{
|
||||
SYS_PRINT(_COLOR_Y "[" _COLOR_END "0x%08X" _COLOR_Y "]" _COLOR_END ": 0x", (unsigned)addr);
|
||||
if (endian)
|
||||
{
|
||||
for (i = 0; i < width; i++)
|
||||
{
|
||||
value[i] = ((uint8_t *)p)[i];
|
||||
SYS_PRINT("%02X", value[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < width; i++)
|
||||
{
|
||||
value[i] = ((uint8_t *)p)[width - 1 - i];
|
||||
SYS_PRINT("%02X", value[i]);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < width; i++)
|
||||
{
|
||||
for (j = 0; j < 8; j++)
|
||||
{
|
||||
if (j % 4 == 0)
|
||||
{
|
||||
SYS_PRINT(" ");
|
||||
if (j % 8 == 0)
|
||||
{
|
||||
SYS_PRINT(" ");
|
||||
}
|
||||
}
|
||||
if (value[i] >> (7 - j) & 1)
|
||||
{
|
||||
SYS_PRINT(" 1");
|
||||
}
|
||||
else
|
||||
{
|
||||
SYS_PRINT(" 0");
|
||||
}
|
||||
}
|
||||
}
|
||||
SYS_PRINT("\n");
|
||||
addr += width;
|
||||
p = &((uint8_t *)p)[width];
|
||||
size -= width;
|
||||
if (size == 0)
|
||||
{
|
||||
for (i = 0; i < 9 + sizeof(void *) * 2 + width * 2 + width * 8 / 4 + lenmax; i++)
|
||||
{
|
||||
SYS_PRINT("=");
|
||||
}
|
||||
SYS_PRINT("\r\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
#undef BITS_PRE_LINE
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
301
components/system/include/sys_types.h
Executable file
301
components/system/include/sys_types.h
Executable file
@@ -0,0 +1,301 @@
|
||||
/**
|
||||
* @file sys_types.h
|
||||
* @author LokLiang (lokliang@163.com)
|
||||
* @brief
|
||||
* @version 0.1
|
||||
* @date 2023-05-01
|
||||
*
|
||||
* @copyright Copyright (c) 2023
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SYS_TYPES_H__
|
||||
#define __SYS_TYPES_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif /* #ifdef __cplusplus */
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL ((void *)0)
|
||||
#endif
|
||||
|
||||
#if defined(__CC_ARM)
|
||||
|
||||
#ifndef __static_inline
|
||||
#define __static_inline static __inline
|
||||
#endif
|
||||
|
||||
#ifndef __section
|
||||
#define __section(X) __attribute__((section(X)))
|
||||
#endif
|
||||
|
||||
#ifndef __used
|
||||
#define __used __attribute__((used))
|
||||
#endif
|
||||
|
||||
#ifndef __weak
|
||||
#define __weak __attribute__((weak))
|
||||
#endif
|
||||
|
||||
#ifndef __naked
|
||||
#define __naked __attribute__((naked))
|
||||
#endif
|
||||
|
||||
#ifndef __packed
|
||||
#define __packed __attribute__((packed))
|
||||
#endif
|
||||
|
||||
#ifndef __aligned
|
||||
#define __aligned(X) __attribute__((aligned(X)))
|
||||
#endif
|
||||
|
||||
#ifndef __likely
|
||||
#define __likely(X) __builtin_expect(!!(X), 1)
|
||||
#endif
|
||||
|
||||
#ifndef __unlikely
|
||||
#define __unlikely(X) __builtin_expect(!!(X), 0)
|
||||
#endif
|
||||
|
||||
#ifndef FALLTHROUGH
|
||||
#define FALLTHROUGH
|
||||
#endif
|
||||
|
||||
#ifndef __nop
|
||||
#define __nop() do { __asm { nop; } } while (0)
|
||||
#endif
|
||||
|
||||
#ifndef __no_optimize
|
||||
#define __no_optimize
|
||||
#endif
|
||||
|
||||
#ifndef __clz
|
||||
#define __clz(VAL) __builtin_clz(VAL);
|
||||
#endif
|
||||
|
||||
#ifndef __typeof
|
||||
#define __typeof(VAR) __typeof__((VAR))
|
||||
#endif
|
||||
|
||||
#ifndef __optimize
|
||||
#define __optimize(X) __attribute__((optimize("O"#X)))
|
||||
#endif
|
||||
|
||||
#elif defined(__GNUC__) /* #if defined(__CC_ARM) */
|
||||
|
||||
#ifndef __static_inline
|
||||
#define __static_inline static inline
|
||||
#endif
|
||||
|
||||
#ifndef __section
|
||||
#define __section(X) __attribute__((section(X)))
|
||||
#endif
|
||||
|
||||
#ifndef __used
|
||||
#define __used __attribute__((used))
|
||||
#endif
|
||||
|
||||
#ifndef __weak
|
||||
#define __weak __attribute__((weak))
|
||||
#endif
|
||||
|
||||
#ifndef __naked
|
||||
#define __naked __attribute__((naked))
|
||||
#endif
|
||||
|
||||
#ifndef __packed
|
||||
#define __packed __attribute__((__packed__))
|
||||
#endif
|
||||
|
||||
#ifndef __aligned
|
||||
#define __aligned(X) __attribute__((__aligned__(X)))
|
||||
#endif
|
||||
|
||||
#ifndef __likely
|
||||
#define __likely(X) __builtin_expect(!!(X), 1)
|
||||
#endif
|
||||
|
||||
#ifndef __unlikely
|
||||
#define __unlikely(X) __builtin_expect(!!(X), 0)
|
||||
#endif
|
||||
|
||||
#ifndef FALLTHROUGH
|
||||
#define FALLTHROUGH __attribute__((fallthrough))
|
||||
#endif
|
||||
|
||||
#ifndef __nop
|
||||
#define __nop() __asm volatile("nop")
|
||||
#endif
|
||||
|
||||
#ifndef __no_optimize
|
||||
#define __no_optimize __attribute__((optimize("O0")))
|
||||
#endif
|
||||
|
||||
#ifndef __clz
|
||||
#define __clz(VAL) ((VAL) == 0 ? 32 : __builtin_clz(VAL))
|
||||
#endif
|
||||
|
||||
#ifndef __typeof
|
||||
#define __typeof(VAR) __typeof__((VAR))
|
||||
#endif
|
||||
|
||||
#ifndef __optimize
|
||||
#define __optimize(X) __attribute__((optimize("O"#X)))
|
||||
#endif
|
||||
|
||||
#else /* #elif defined(__GNUC__) */
|
||||
|
||||
#define __static_inline static inline
|
||||
|
||||
#define __no_init
|
||||
|
||||
#define __nop() __nop
|
||||
|
||||
#define __no_optimize
|
||||
|
||||
#define __clz(VAL) __builtin_clz(VAL);
|
||||
|
||||
#endif /* #elif defined(__GNUC__) */
|
||||
|
||||
#ifndef __ARRAY_SIZE
|
||||
#define __ARRAY_SIZE(ARRAY) (sizeof(ARRAY) / sizeof((ARRAY)[0]))
|
||||
#endif
|
||||
|
||||
#ifndef __no_init
|
||||
#define __no_init __section(".noinitialized")
|
||||
#endif
|
||||
|
||||
#ifndef __ram_text
|
||||
#define __ram_text __section(".ram_text")
|
||||
#endif
|
||||
|
||||
#ifndef __IM
|
||||
#define __IM volatile const /*! Defines 'read only' structure member permissions */
|
||||
#endif
|
||||
#ifndef __OM
|
||||
#define __OM volatile /*! Defines 'write only' structure member permissions */
|
||||
#endif
|
||||
#ifndef __IOM
|
||||
#define __IOM volatile /*! Defines 'read / write' structure member permissions */
|
||||
#endif
|
||||
|
||||
#ifndef sys_le16_to_cpu
|
||||
#define _b_swap_16(X) ((u16_t)((((X) >> 8) & 0xff) | (((X)&0xff) << 8)))
|
||||
|
||||
#define _b_swap_32(X) ((u32_t)((((X) >> 24) & 0xff) | \
|
||||
(((X) >> 8) & 0xff00) | \
|
||||
(((X)&0xff00) << 8) | \
|
||||
(((X)&0xff) << 24)))
|
||||
|
||||
#define _b_swap_64(X) ((u64_t)((((X) >> 56) & 0xff) | \
|
||||
(((X) >> 40) & 0xff00) | \
|
||||
(((X) >> 24) & 0xff0000) | \
|
||||
(((X) >> 8) & 0xff000000) | \
|
||||
(((X)&0xff000000) << 8) | \
|
||||
(((X)&0xff0000) << 24) | \
|
||||
(((X)&0xff00) << 40) | \
|
||||
(((X)&0xff) << 56)))
|
||||
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
#define sys_le16_to_cpu(VAL) (VAL)
|
||||
#define sys_le32_to_cpu(VAL) (VAL)
|
||||
#define sys_le64_to_cpu(VAL) (VAL)
|
||||
#define sys_cpu_to_le16(VAL) (VAL)
|
||||
#define sys_cpu_to_le32(VAL) (VAL)
|
||||
#define sys_cpu_to_le64(VAL) (VAL)
|
||||
#define sys_be16_to_cpu(VAL) _b_swap_16(VAL)
|
||||
#define sys_be32_to_cpu(VAL) _b_swap_32(VAL)
|
||||
#define sys_be64_to_cpu(VAL) _b_swap_64(VAL)
|
||||
#define sys_cpu_to_be16(VAL) _b_swap_16(VAL)
|
||||
#define sys_cpu_to_be32(VAL) _b_swap_32(VAL)
|
||||
#define sys_cpu_to_be64(VAL) _b_swap_64(VAL)
|
||||
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
#define sys_le16_to_cpu(VAL) _b_swap_16(VAL)
|
||||
#define sys_le32_to_cpu(VAL) _b_swap_32(VAL)
|
||||
#define sys_le64_to_cpu(VAL) _b_swap_64(VAL)
|
||||
#define sys_cpu_to_le16(VAL) _b_swap_16(VAL)
|
||||
#define sys_cpu_to_le32(VAL) _b_swap_32(VAL)
|
||||
#define sys_cpu_to_le64(VAL) _b_swap_64(VAL)
|
||||
#define sys_be16_to_cpu(VAL) (VAL)
|
||||
#define sys_be32_to_cpu(VAL) (VAL)
|
||||
#define sys_be64_to_cpu(VAL) (VAL)
|
||||
#define sys_cpu_to_be16(VAL) (VAL)
|
||||
#define sys_cpu_to_be32(VAL) (VAL)
|
||||
#define sys_cpu_to_be64(VAL) (VAL)
|
||||
#else
|
||||
#error "Unknown byte order"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef uint8_t u8_t ;
|
||||
typedef uint16_t u16_t ;
|
||||
typedef uint32_t u32_t ;
|
||||
typedef int8_t s8_t ;
|
||||
typedef int16_t s16_t ;
|
||||
typedef int32_t s32_t ;
|
||||
typedef int64_t s64_t ;
|
||||
typedef volatile uint8_t vu8_t ;
|
||||
typedef volatile uint16_t vu16_t ;
|
||||
typedef volatile uint32_t vu32_t ;
|
||||
typedef volatile uint64_t vu64_t ;
|
||||
typedef volatile int8_t vs8_t ;
|
||||
typedef volatile int16_t vs16_t ;
|
||||
typedef volatile int32_t vs32_t ;
|
||||
typedef volatile int64_t vs64_t ;
|
||||
typedef volatile signed vint ;
|
||||
typedef unsigned uint ;
|
||||
typedef volatile unsigned vuint ;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TYPES_NO_ERR = 0,
|
||||
TYPES_TIMEOUT,
|
||||
TYPES_NO_MEM,
|
||||
TYPES_HAL_ERR,
|
||||
TYPES_ERROR = -1,
|
||||
} types_err_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TYPES_RESET = 0,
|
||||
TYPES_SET = 1,
|
||||
} types_flag_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TYPES_DISABLE = 0,
|
||||
TYPES_ENABLE = 1,
|
||||
} types_ctrl_t;
|
||||
|
||||
#ifndef __WRITEBITS
|
||||
#define __WRITEBITS(P, INDEX, WIDE, VALUE) (*(vuint *)(P) = (*(vuint *)(P) & ~(~(-1u << (WIDE)) << (INDEX))) ^ (((VALUE) & ~(-1u << (WIDE))) << (INDEX)))
|
||||
#endif
|
||||
|
||||
#ifndef __READBITS
|
||||
#define __READBITS(VAR, INDEX, WIDE) (((VAR) >> (INDEX)) & ~(-1u << (WIDE)))
|
||||
#endif
|
||||
|
||||
__static_inline void writebits(volatile void *dest, u8_t index, u8_t bitwide, uint value)
|
||||
{
|
||||
while(index + bitwide > sizeof(vuint) * 8);
|
||||
while(value >= 1 << bitwide);
|
||||
__WRITEBITS(dest, index, bitwide, value);
|
||||
}
|
||||
|
||||
__static_inline uint readbits(uint var, u8_t index, u8_t bitwide)
|
||||
{
|
||||
return __READBITS(var, index, bitwide);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif /* #ifdef __cplusplus */
|
||||
|
||||
#endif
|
||||
109
components/system/source/k_kit/README.md
Executable file
109
components/system/source/k_kit/README.md
Executable file
@@ -0,0 +1,109 @@
|
||||
[简要](../../../../README.md)
|
||||
|
||||
# 微内核 k_kit
|
||||
|
||||
> k_kit 以下简称 kit。kit 可以理解成是一个实时内核中的软定时器模块的强化版。
|
||||
基于此设计的程序就是由所有软定时器组成的集合,这些集合既可作为一个完整的工程,也可以作为一个线程模块,使用非常灵活。
|
||||
|
||||
## 特点
|
||||
- 是一个极小的,由事件驱动的,管理任务的微内核;
|
||||
- 介于裸机与实时内核之间,适用于资源受限的微型系统的同时,尽可能提供类似实时内核接口和管理方式;
|
||||
- 极低的跨平台需求,只需要实现几个简单的接口,即可在任何平台上运行;
|
||||
- 所有功能模块都有独立的对象,所有对象动通过态申请和销毁;
|
||||
- 极短的、固定的关中断时间,有效保障硬实时性;
|
||||
- 基于 kit 设计的工程可无缝扩充到 RTK 实时内核中 [点击查看 RTK](../../README.md);
|
||||
|
||||
## 文件结构
|
||||
```bash
|
||||
...
|
||||
└── kit # 本目录
|
||||
├── k_kit.c # kit 的所有实现代码。
|
||||
├── k_kit.h # 完整的 kit 的功能接口
|
||||
└── kk.h # 跨内核接口,与实时内核中 RTK 中的 `rtk_kk.h` 保持一致
|
||||
```
|
||||
|
||||
## 模块简介
|
||||
|
||||
### `work`
|
||||
- work 是任务管理的对象,数据结构由 k_work_t 封装,在创建对象时设置实现函数;
|
||||
- 任务拥有: 运行、延时、挂起、堵塞 的能力;
|
||||
- 所有任务都由队列函数 k_work_q_handler() 执行调用管管理;
|
||||
- 所有任务可设置由通讯模块唤醒;
|
||||
- 所有任务默认附带一个接收邮箱;
|
||||
- 所有任务函数必须返回;
|
||||
- 所有任务都允许设置优先级,但不可抢断;
|
||||
|
||||
#### *mbox*
|
||||
- mbox 是 work 附带的一个功能的扩展功能,用法与 fifo 类似;
|
||||
- 邮箱在使用前需要被创建,每个任务最多只能有一个邮箱;
|
||||
- 邮件内存从堆中申请,传递的是指针,与 fifo 不可混用;
|
||||
- 一个新邮件被提交时,对应的任务一定被唤醒;
|
||||
- 提取后的邮件在任务函数退出后被自动删除;
|
||||
|
||||
### `timer`
|
||||
- timer 是软定时器的管理对象,数据结构由 k_timer_t 封装,在创建对象时设置实现函数;
|
||||
- 软定时器的本质是在 work 的基础上添加一些时间特性的任务;
|
||||
- 软定时器拥有: 运行、延时、挂起 的能力;
|
||||
- 所有软定时器都由队列函数 k_timer_q_handler() 执行调用管管理;
|
||||
- 所有软定时器函数必须返回;
|
||||
- 所有软定时器都允许设置优先级,但不可抢断;
|
||||
|
||||
### work 与 timer 比较
|
||||
| | work | timer |
|
||||
| :------: | :----------------: | :-----------------: |
|
||||
| 入口 | k_work_q_handler() | k_timer_q_handler() |
|
||||
| 运行 | 是 | 是 |
|
||||
| 延时 | 是 | 是 |
|
||||
| 挂起 | 是 | 是 |
|
||||
| 堵塞 | 是 | 不支持 |
|
||||
| 优先级 | 0 .. 7 | 0 .. 7 |
|
||||
| mbox | 可用,默认唤醒 | 仅发送 |
|
||||
| fifo | 可用,注册唤醒 | 可用,不支持唤醒 |
|
||||
| queue | 可用,注册唤醒 | 可用,不支持唤醒 |
|
||||
| pipe | 可用,注册唤醒 | 可用,不支持唤醒 |
|
||||
| log | 可用 | 不可用 |
|
||||
|
||||
### *IPC*
|
||||
|
||||
- kit 目前包含了三种常用的独立对象的通讯模块 `fifo`, `queue`, `pipe` 和 work 专用的模块 `mbox`;
|
||||
|
||||
| | fifo | queue | pipe | mbox |
|
||||
| :------------: | :-------: | :-------: | :------: | :------: |
|
||||
| 对象 | k_fifo_t | k_queue_t | k_pipe_t | k_work_t |
|
||||
| 数据缓存 | 堆 | 独立 | 独立 | 堆 |
|
||||
| 数据吞吐 | 中 | 慢 | 快 | 中 |
|
||||
| 数据交换 | 指针 | 副本 | 副本 | 指针 |
|
||||
| 单位长度 | 不限 | 固定 | 字节 | 不限 |
|
||||
| 总长度 | 不限 | 固定 | 固定 | 不限 |
|
||||
| 在中断申请缓存 | 禁止 | 可用 | 不需要 | 禁止 |
|
||||
| work | 完整可用 | 完整可用 | 完整可用 | 完整可用 |
|
||||
| timer | 仅收发 | 仅收发 | 仅收发 | 仅发送 |
|
||||
| isr | 仅收发 | 仅收发 | 仅收发 | 仅发送 |
|
||||
|
||||
## 调度机制
|
||||
|
||||
> 每个 work 对象都对应一个勾子函数为任务,由入口 k_work_q_handler() 管理(软定时器同理),通过三个关键链表的操作,调用对应的勾子函数。
|
||||
> 主要由接口 k_work_submit(), k_work_resume(), k_work_suspend(), k_work_later() 等触发有关链表的操作。
|
||||
|
||||
- dlist_t event_list;
|
||||
> dlist_t event_list 是一个双向链表,由上述的接口插入,在队列管理接口中取出;
|
||||
|
||||
- slist_t ready_list[8];
|
||||
> dlist_t event_list 共8个成员的单向链表,每个成员表示一个优先级,由队列管理接口使用;
|
||||
|
||||
- slist_t delayed_list;
|
||||
> slist_t delayed_list 是一个单向链表,由队列管理接口使用;
|
||||
|
||||
- 触发调试的过程:
|
||||
1. 在接口 k_work_submit() 中把任务对象添加超时信息并插入到 event_list 中;
|
||||
2. k_work_q_handler() 检测 delayed_list 如果有超时的任务,插入到 ready_list 中;
|
||||
3. k_work_q_handler() 总是在 event_list 取出任务对象,如果:
|
||||
- 任务已超时:插入到 ready_list;
|
||||
- 任务未超时:按时间顺序,插入到 delayed_list;
|
||||
4. 在 ready_list 中查找,如果:
|
||||
- 存在任务:从链中删除并执行任务;
|
||||
- 没有任务:无动作;
|
||||
5. 返回下个超时的任务的剩余时间;
|
||||
|
||||
## END
|
||||
|
||||
4437
components/system/source/k_kit/k_kit.c
Executable file
4437
components/system/source/k_kit/k_kit.c
Executable file
File diff suppressed because it is too large
Load Diff
311
components/system/source/k_kit/k_kit.h
Executable file
311
components/system/source/k_kit/k_kit.h
Executable file
@@ -0,0 +1,311 @@
|
||||
/**
|
||||
* @file k_kit.h
|
||||
* @author LokLiang (lokliang@163.com)
|
||||
* @brief 裸机版微内核
|
||||
* @version 1.1.0
|
||||
*
|
||||
* @copyright Copyright (c) 2022
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __K_KIT_H__
|
||||
#define __K_KIT_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
typedef int k_err_t;
|
||||
typedef int k_tick_t;
|
||||
|
||||
typedef void* k_hdl_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
k_hdl_t hdl;
|
||||
} k_work_q_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void *(*malloc)(size_t); // 执行申请内存(内部已通过 scheduler_disable()/scheduler_enable() 进行临界保护)
|
||||
void (*free)(void *); // 执行释放内存(内部已通过 scheduler_disable()/scheduler_enable() 进行临界保护)
|
||||
unsigned (*get_sys_ticks)(void); // 获取当前系统时间
|
||||
unsigned (*interrupt_save)(void); // 禁止中断
|
||||
void (*interrupt_restore)(unsigned); // 恢复中断
|
||||
|
||||
void (*scheduler_disable)(void); // 禁止线程的调度(实时内核使用,非实时内核使用可设置为NULL)
|
||||
void (*scheduler_enable)(void); // 恢复线程的调度(实时内核使用,非实时内核使用可设置为NULL)
|
||||
k_work_q_t *(*get_work_q_hdl)(void); // 获取当前执行 k_work_q_handler() 的线程的 k_work_q_t 对象(实时内核使用,非实时内核使用可设置为NULL)
|
||||
void (*thread_sleep)(k_tick_t sleep_ticks); // 使线程休眠(实时内核使用,非实时内核使用可设置为NULL)
|
||||
} k_init_t;
|
||||
|
||||
void k_entry(const k_init_t *init_struct); // 初始化并进入微内核模式
|
||||
|
||||
void k_init(const k_init_t *init_struct); // 初始化微内核
|
||||
void k_deinit(void); // 取消初始化微内核
|
||||
|
||||
/** @defgroup work queue
|
||||
* @{
|
||||
*/
|
||||
|
||||
typedef void (*k_work_q_fn)(void *arg);
|
||||
|
||||
extern k_work_q_t *default_work_q_hdl; // 预留的一个工默认的作队列对象内存,初始值为内部默认的对象
|
||||
|
||||
k_tick_t k_work_q_handler(k_work_q_t *work_q_handle); // 工作队列执行入口
|
||||
|
||||
k_err_t k_work_q_create(k_work_q_t *work_q_handle); // 创建一个工作队列的对象
|
||||
void k_work_q_delete(k_work_q_t *work_q_handle); // 删除一个工作队列的对象
|
||||
|
||||
void k_work_q_resume_regist(k_work_q_t *work_q_handle, k_work_q_fn work_q_resume, void *arg); // 注册一个函数:当有任务被提交时,此回调函数将被自动执行
|
||||
|
||||
bool k_work_q_is_valid(k_work_q_t *work_q_handle); // 获取工作队列是否有效
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup work
|
||||
* @{
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
k_hdl_t hdl;
|
||||
} k_work_t;
|
||||
|
||||
typedef void (*k_work_fn)(void *arg);
|
||||
|
||||
void k_work_hook(k_work_q_t *work_q_handle, k_work_fn hook); // 设置切换任务时,进入和退出任务时回调函数
|
||||
|
||||
bool k_work_q_delayed_state(k_work_q_t *work_q_handle); // 获取是否有正在延时状态的任务
|
||||
bool k_work_q_ready_state(k_work_q_t *work_q_handle); // 获取工作队列中是否有就绪的任务
|
||||
|
||||
k_err_t k_work_create(k_work_t *work_handle,
|
||||
const char *name,
|
||||
k_work_fn work_route,
|
||||
void *arg,
|
||||
uint8_t priority);
|
||||
|
||||
void k_work_delete(k_work_t *work_handle); // 删除由工作队列管理的任务
|
||||
|
||||
bool k_work_is_valid(k_work_t *work_handle); // 获取任务对象是否有效
|
||||
bool k_work_is_pending(k_work_t *work_handle); // 获取任务是否在就绪或延时的状态
|
||||
k_tick_t k_work_time_remain(k_work_t *work_handle); // 获取任务距离下个执行的剩余时间
|
||||
|
||||
void k_work_submit(k_work_q_t *work_q_handle, k_work_t *work_handle, k_tick_t delay_ticks); // 使任务在指定工作队列中在指定时间后就绪
|
||||
void k_work_resume(k_work_t *work_handle, k_tick_t delay_ticks); // 唤醒任务。注意需要先使用 k_work_submit 绑定一个 work_q_handle
|
||||
void k_work_suspend(k_work_t *work_handle); // 挂起任务,任务不会被删除
|
||||
|
||||
void k_work_later(k_tick_t delay_ticks); // 延时多少个系统节拍后再执行本任务
|
||||
void k_work_later_until(k_tick_t delay_ticks); // 从最后一次唤醒的时间算起,延时多少个系统节拍后再执行本任务(固定周期的延时)
|
||||
void k_work_yield(k_tick_t delay_ticks); // 释放一次CPU的使用权,不调度低于当前任务优先级的任务
|
||||
void k_work_sleep(k_tick_t delay_ticks); // 释放一次CPU的使用权,可调度低于当前任务优先级的任务
|
||||
|
||||
k_work_t *k_get_curr_work_handle(k_work_q_t *work_q_handle); // 查询最近一次执行的任务
|
||||
|
||||
k_err_t k_work_mbox_create(k_work_t *work_handle); // 创建任务的邮箱
|
||||
void k_work_mbox_delete(k_work_t *work_handle); // 删除任务的邮箱
|
||||
|
||||
void *k_work_mbox_alloc(k_work_t *work_handle, size_t size); // 申请一个邮件
|
||||
k_err_t k_work_mbox_cancel(void *mbox); // 取消已申请的邮件
|
||||
k_err_t k_work_mbox_submit(void *mbox); // 发送邮件
|
||||
void *k_work_mbox_take(void); // 提取邮件
|
||||
void *k_work_mbox_peek(void); // 查询邮件
|
||||
void k_work_mbox_clr(void); // 清空任务的所有邮件
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup timer queue
|
||||
* @{
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
k_hdl_t hdl;
|
||||
} k_timer_q_t;
|
||||
|
||||
typedef void (*k_timer_q_fn)(void *arg);
|
||||
|
||||
extern k_timer_q_t *default_timer_q_hdl; // 预留的一个工默认的软定时器队列对象内存,初始值为内部默认的对象
|
||||
|
||||
k_tick_t k_timer_q_handler(k_timer_q_t *timer_q_handle); // 软定时器队列执行入口
|
||||
|
||||
k_err_t k_timer_q_create(k_timer_q_t *timer_q_handle); // 创建一个软定时器队列的对象
|
||||
void k_timer_q_delete(k_timer_q_t *timer_q_handle); // 删除一个软定时器队列的对象
|
||||
|
||||
void k_timer_q_resume_regist(k_timer_q_t *timer_q_handle, k_timer_q_fn timer_q_resume, void *arg); // 注册一个函数:当有任务被提交时,此回调函数将被自动执行
|
||||
|
||||
bool k_timer_q_is_valid(k_timer_q_t *timer_q_handle); // 获取软定时器队列是否有效
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup timer
|
||||
* @{
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
k_hdl_t hdl;
|
||||
} k_timer_t;
|
||||
|
||||
typedef void (*k_timer_fn)(void *arg);
|
||||
|
||||
bool k_timer_q_delayed_state(k_timer_q_t *timer_q_handle); // 获取是否有正在延时状态的定时器
|
||||
bool k_timer_q_ready_state(k_timer_q_t *timer_q_handle); // 获取软定时器队列中是否有就绪的定时器
|
||||
|
||||
k_err_t k_timer_create(k_timer_t *timer_handle,
|
||||
k_timer_q_t *timer_q_handle,
|
||||
k_timer_fn timer_route,
|
||||
void *arg,
|
||||
uint8_t priority);
|
||||
|
||||
void k_timer_delete(k_timer_t *timer_handle);
|
||||
|
||||
void k_timer_set_period(k_timer_t *timer_handle, bool periodic, k_tick_t period); // 设置定时器的自动重装值
|
||||
void k_timer_start(k_timer_t *timer_handle, k_tick_t delay_ticks); // 使定时器在指定软定时器队列中在指定时间后就绪
|
||||
void k_timer_stop(k_timer_t *timer_handle); // 挂起定时器,定时器不会被删除
|
||||
|
||||
k_err_t k_timer_newsubmit(k_timer_q_t *timer_q_handle, k_timer_fn timer_route, void *arg, k_tick_t delay_ticks); // 生成一个临时定时器,执行完自动删除
|
||||
k_err_t k_timer_resubmit(k_timer_q_t *timer_q_handle, k_timer_fn timer_route, void *arg, k_tick_t delay_ticks); // 删除并重新生成一个新的临时定时器,执行完自动删除
|
||||
void k_timer_cancel(k_timer_q_t *timer_q_handle, k_timer_fn timer_route); // 立即删除临时定时器
|
||||
|
||||
bool k_timer_is_valid(k_timer_t *timer_handle); // 获取定时器对象是否有效
|
||||
bool k_timer_is_pending(k_timer_t *timer_handle); // 获取定时器是否在就绪或延时的状态
|
||||
bool k_timer_is_periodic(k_timer_t *timer_handle); // 查询当前是否自动重装
|
||||
k_tick_t k_timer_get_period(k_timer_t *timer_handle); // 查询当前的自动重装值
|
||||
k_tick_t k_timer_time_remain(k_timer_t *timer_handle); // 获取定时器距离下个执行的剩余时间
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup fifo
|
||||
* @{
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
k_hdl_t hdl;
|
||||
} k_fifo_t;
|
||||
|
||||
k_err_t k_fifo_q_create(k_fifo_t *fifo_handle); // 创建一个 FIFO 对象
|
||||
void k_fifo_q_delete(k_fifo_t *fifo_handle); // 删除一个 FIFO 的对象
|
||||
void k_fifo_q_clr(k_fifo_t *fifo_handle); // 清除 FIFO 内的所有数据
|
||||
|
||||
bool k_fifo_q_is_valid(k_fifo_t *fifo_handle); // 获取 FIFO 对象是否有效
|
||||
|
||||
void k_fifo_q_regist(k_fifo_t *fifo_handle, k_work_t *work_handle, k_tick_t delay_ticks); // 注册当队列非空时被唤醒的任务
|
||||
void k_fifo_q_unregist(k_fifo_t *fifo_handle); // 取消注册任务
|
||||
|
||||
void *k_fifo_alloc(size_t size); // 申请可用于 FIFO 的数据结构
|
||||
k_err_t k_fifo_free(void *data); // 释放由 k_fifo_alloc() 申请的数据结构
|
||||
|
||||
k_err_t k_fifo_put(k_fifo_t *fifo_handle, void *data); // 把数据结构压入到 FIFO 中
|
||||
void *k_fifo_take(k_fifo_t *fifo_handle); // 从 FIFO 中弹出最先压入的数据
|
||||
void *k_fifo_peek_head(k_fifo_t *fifo_handle); // 查询 FIFO 中头部的数据地址
|
||||
void *k_fifo_peek_tail(k_fifo_t *fifo_handle); // 查询 FIFO 中尾部的数据地址
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup queue
|
||||
* @{
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
k_hdl_t hdl;
|
||||
} k_queue_t;
|
||||
|
||||
k_err_t k_queue_create(k_queue_t *queue_handle, size_t queue_length, size_t item_size); // 创建一个 QUEUE 对象
|
||||
void k_queue_delete(k_queue_t *queue_handle); // 删除一个 QUEUE 的对象
|
||||
void k_queue_clr(k_queue_t *queue_handle); // 清除 QUEUE 内的所有数据
|
||||
|
||||
bool k_queue_is_valid(k_queue_t *queue_handle); // 获取 QUEUE 对象是否有效
|
||||
|
||||
void k_queue_regist(k_queue_t *queue_handle, k_work_t *work_handle, k_tick_t delay_ticks); // 注册当队列非空时被唤醒的任务
|
||||
void k_queue_unregist(k_queue_t *queue_handle); // 取消注册任务
|
||||
|
||||
k_err_t k_queue_recv(k_queue_t *queue_handle, void *dst); // 接收并复制数据
|
||||
k_err_t k_queue_send(k_queue_t *queue_handle, const void *src); // 复制数据并发送
|
||||
|
||||
void *k_queue_alloc(k_queue_t *queue_handle); // 申请可用于 QUEUE 的数据结构
|
||||
k_err_t k_queue_free(void *data); // 释放由 k_queue_alloc() 申请的数据结构
|
||||
k_err_t k_queue_put(void *data); // 把数据压入到 QUEUE 中
|
||||
void *k_queue_take(k_queue_t *queue_handle); // 从 QUEUE 中弹出最先压入的数据
|
||||
|
||||
void *k_queue_peek_head(k_queue_t *queue_handle); // 查询 QUEUE 中头部的数据地址
|
||||
void *k_queue_peek_tail(k_queue_t *queue_handle); // 查询 QUEUE 中尾部的数据地址
|
||||
|
||||
size_t k_queue_get_item_size(k_queue_t *queue_handle); // 读回 k_queue_create() 中设置的 item_size 的值
|
||||
|
||||
k_queue_t *k_queue_read_handle(void *data); // 查询已申请数据的所属队列句柄
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup pipe
|
||||
* @{
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
k_hdl_t hdl;
|
||||
} k_pipe_t;
|
||||
|
||||
k_err_t k_pipe_create(k_pipe_t *pipe_handle, size_t pipe_size); // 创一个管道对象
|
||||
void k_pipe_delete(k_pipe_t *pipe_handle); // 删除一个管道对象
|
||||
void k_pipe_clr(k_pipe_t *pipe_handle); // 清空管道的数据
|
||||
|
||||
bool k_pipe_is_valid(k_pipe_t *pipe_handle); // 获取 PIPE 对象是否有效
|
||||
|
||||
void k_pipe_regist(k_pipe_t *pipe_handle, k_work_t *work_handle, k_tick_t delay_ticks); // 注册当队列非空时被唤醒的任务
|
||||
void k_pipe_unregist(k_pipe_t *pipe_handle); // 取消注册任务
|
||||
|
||||
size_t k_pipe_poll_write(k_pipe_t *pipe_handle, uint8_t data); // 写一个字节到缓存中(写入缓存),返回实际复制成功的字节数
|
||||
size_t k_pipe_fifo_fill(k_pipe_t *pipe_handle, const void *data, size_t size); // 把内存数据复制到缓存中(写入缓存),返回实际复制成功的字节数
|
||||
size_t k_pipe_poll_read(k_pipe_t *pipe_handle, uint8_t *data); // 从缓存复制一个字节到指定地址中,返回 0 表示缓存空
|
||||
size_t k_pipe_fifo_read(k_pipe_t *pipe_handle, void *data, size_t size); // 从管道中复制数据到内存(从缓存读取),返回实际复制成功的字节数。注:参数 data 值可以为 NULL,此时不复制数据,只释放相应的数据量
|
||||
|
||||
bool k_pipe_is_ne(k_pipe_t *pipe_handle); // 获取管道非空, true 有数据
|
||||
size_t k_pipe_get_valid_size(k_pipe_t *pipe_handle); // 获取管道的数据大小(字节数)
|
||||
size_t k_pipe_get_empty_size(k_pipe_t *pipe_handle); // 获取管道的剩余空间(字节数)
|
||||
|
||||
void k_pipe_peek_valid(k_pipe_t *pipe_handle, void **dst_base, size_t *dst_size); // 获取当前已写入的连续的内存信息
|
||||
void k_pipe_peek_empty(k_pipe_t *pipe_handle, void **dst_base, size_t *dst_size); // 获取当前空闲的连续的内存信息
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @defgroup miscellaneous
|
||||
* @{
|
||||
*/
|
||||
|
||||
k_tick_t k_get_sys_ticks(void); // 获取当前系统时间
|
||||
void k_disable_interrupt(void); // 禁止中断(屏蔽中断并自动记录嵌套数)
|
||||
void k_enable_interrupt(void); // 恢复中断(根据嵌套数自动恢复中断)
|
||||
|
||||
void k_log_sched(void); // 打印当前调度日志
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
153
components/system/source/k_kit/kk.h
Executable file
153
components/system/source/k_kit/kk.h
Executable file
@@ -0,0 +1,153 @@
|
||||
/**
|
||||
* @file kk.h
|
||||
* @author lokliang
|
||||
* @brief k_kit.h 衍生的易用接口,简化部分接口中的参数,去除不常用的接口
|
||||
* @version 1.0
|
||||
* @date 2022-12-09
|
||||
* @date 2021-01-13
|
||||
*
|
||||
* @copyright Copyright (c) 2021
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __KK_H__
|
||||
#define __KK_H__
|
||||
|
||||
#include "k_kit.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
typedef k_err_t kk_err_t;
|
||||
typedef k_tick_t kk_time_t;
|
||||
typedef k_work_q_t kk_work_q_t;
|
||||
typedef k_work_t kk_work_t;
|
||||
typedef k_timer_t kk_timer_t;
|
||||
typedef k_fifo_t kk_fifo_t;
|
||||
typedef k_queue_t kk_queue_t;
|
||||
typedef k_pipe_t kk_pipe_t;
|
||||
|
||||
#define WORK_Q_HDL default_work_q_hdl
|
||||
#define TIMER_Q_HDL default_timer_q_hdl
|
||||
|
||||
#define kk_handler() k_work_q_handler(WORK_Q_HDL) // 工作队列执行入口
|
||||
#define kk_timer_handler() k_timer_q_handler(TIMER_Q_HDL) // 软定时器队列执行入口
|
||||
|
||||
#define kk_work_q_delayed_state() k_work_q_delayed_state(WORK_Q_HDL) // 获取是否有正在延时状态的任务
|
||||
#define kk_work_q_ready_state() k_work_q_ready_state(WORK_Q_HDL) // 获取工作队列中是否有就绪的任务
|
||||
#define kk_work_q_delete() k_work_q_delete(WORK_Q_HDL) // 删除一个工作队列的对象
|
||||
#define kk_work_q_is_valid() k_work_q_is_valid(WORK_Q_HDL) // 获取工作队列是否有效
|
||||
|
||||
#define kk_work_create(work_handle, work_route, arg, priority) k_work_create(work_handle, #work_route, work_route, arg, priority) // 创建由工作队列管理的任务
|
||||
#define kk_work_delete(work_handle) k_work_delete(work_handle) // 删除由工作队列管理的任务
|
||||
#define kk_work_submit(work_q_handle, work_handle, delay) k_work_submit(work_q_handle, work_handle, delay) // 多少时间后唤醒任务
|
||||
|
||||
#define kk_work_is_valid(work_handle) k_work_is_valid(work_handle) // 获取任务对象是否有效
|
||||
#define kk_work_is_pending(work_handle) k_work_is_pending(work_handle) // 获取任务是否在就绪或延时的状态
|
||||
#define kk_work_time_remain(work_handle) k_work_time_remain(work_handle) // 获取任务距离下个执行的剩余时间
|
||||
|
||||
#define kk_timer_create(timer_handle, timer_route, arg) k_timer_create(timer_handle, TIMER_Q_HDL, timer_route, arg, 0) // 创建由软定时器队列管理的定时器任务
|
||||
#define kk_timer_delete(timer_handle) k_timer_delete(timer_handle) // 删除由软定时器队列管理的定时器任务
|
||||
|
||||
#define kk_timer_start(timer_handle, periodic, period) do { k_timer_set_period(timer_handle, periodic, period); k_timer_start(timer_handle, period); } while (0) // 启动定时器
|
||||
#define kk_timer_stop(timer_handle) k_timer_stop(timer_handle) // 挂起定时器,定时器不会被删除
|
||||
|
||||
#define kk_timer_is_valid(timer_handle) k_timer_is_valid(timer_handle) // 获取定时器对象是否有效
|
||||
#define kk_timer_is_pending(timer_handle) k_timer_is_pending(timer_handle) // 获取定时器是否在就绪或延时的状态
|
||||
#define kk_timer_time_remain(timer_handle) k_timer_time_remain(timer_handle) // 获取定时器距离下个执行的剩余时间
|
||||
|
||||
#define kk_work_mbox_create(work_handle) k_work_mbox_create(work_handle) // 创建任务的邮箱
|
||||
#define kk_work_mbox_delete(work_handle) k_work_mbox_delete(work_handle) // 删除任务的邮箱
|
||||
|
||||
#define kk_fifo_q_create(fifo_handle) k_fifo_q_create(fifo_handle) // 创建一个FIFO对象
|
||||
#define kk_fifo_q_delete(fifo_handle) k_fifo_q_delete(fifo_handle) // 删除一个FIFO的对象
|
||||
#define kk_fifo_q_clr(fifo_handle) k_fifo_q_clr(fifo_handle) // 清除FIFO内的所有数据
|
||||
#define kk_fifo_q_is_valid(fifo_handle) k_fifo_q_is_valid(fifo_handle) // 获取 FIFO 对象是否有效
|
||||
#define kk_fifo_q_regist(fifo_handle, work_handle, ticks) k_fifo_q_regist(fifo_handle, work_handle, ticks) // 注册当队列非空时被唤醒的任务
|
||||
|
||||
#define kk_queue_create(queue_handle, queue_length, item_size) k_queue_create(queue_handle, queue_length, item_size) // 创建一个QUEUE对象
|
||||
#define kk_queue_delete(queue_handle) k_queue_delete(queue_handle) // 删除一个QUEUE的对象
|
||||
#define kk_queue_clr(queue_handle) k_queue_clr(queue_handle) // 清除QUEUE内的所有数据
|
||||
#define kk_queue_is_valid(queue_handle) k_queue_is_valid(queue_handle) // 获取 QUEUE 对象是否有效
|
||||
#define kk_queue_regist(queue_handle, work_handle, ticks) k_queue_regist(queue_handle, work_handle, ticks) // 注册当队列非空时被唤醒的任务
|
||||
|
||||
#define kk_pipe_create(pipe_handle, pipe_size) k_pipe_create(pipe_handle, pipe_size) // 创一个管道对象
|
||||
#define kk_pipe_delete(pipe_handle) k_pipe_delete(pipe_handle) // 删除一个管道对象
|
||||
#define kk_pipe_clr(pipe_handle) k_pipe_clr(pipe_handle) // 清空管道的数据
|
||||
#define kk_pipe_is_valid(pipe_handle) k_pipe_is_valid(pipe_handle) // 获取 PIPE 对象是否有效
|
||||
#define kk_pipe_regist(pipe_handle, work_handle, ticks) k_pipe_regist(pipe_handle, work_handle, ticks) // 注册当队列非空时被唤醒的任务
|
||||
|
||||
#define kk_work_resume(work_handle, delay) k_work_resume(work_handle, delay) // 唤醒任务。注意需要先使用 k_work_submit 绑定一个 work_q_handle
|
||||
#define kk_work_suspend(work_handle) k_work_suspend(work_handle) // 挂起任务,任务不会被删除
|
||||
#define kk_work_later(delay) k_work_later(delay) // 设置下个执行延时
|
||||
#define kk_work_later_until(delay) k_work_later_until(delay) // 从最后一次唤醒的时间算起,延时多少个系统节拍后再执行本任务(固定周期的延时)
|
||||
#define kk_work_yield(delay) k_work_yield(delay) // 释放一次CPU的使用权,不调度低于当前任务优先级的任务
|
||||
#define kk_work_sleep(delay) k_work_sleep(delay) // 释放一次CPU的使用权,可调度低于当前任务优先级的任务
|
||||
|
||||
#define kk_work_mbox_alloc(work_handle, size) k_work_mbox_alloc(work_handle, size) // 申请一个邮件
|
||||
#define kk_work_mbox_cancel(mbox) k_work_mbox_cancel(mbox) // 取消已申请的邮件
|
||||
#define kk_work_mbox_submit(mbox) k_work_mbox_submit(mbox) // 发送邮件
|
||||
#define kk_work_mbox_take() k_work_mbox_take() // 提取邮件
|
||||
#define kk_work_mbox_peek() k_work_mbox_peek() // 查询邮件
|
||||
#define kk_work_mbox_clr() k_work_mbox_clr() // 清空任务的所有邮件
|
||||
|
||||
#define kk_fifo_alloc(size) k_fifo_alloc(size) // 申请可用于FIFO的数据结构
|
||||
#define kk_fifo_free(data) k_fifo_free(data) // 释放由 kk_fifo_alloc() 申请的数据结构
|
||||
#define kk_fifo_put(fifo_handle, data) k_fifo_put(fifo_handle, data) // 把数据结构压入到FIFO中
|
||||
#define kk_fifo_take(fifo_handle) k_fifo_take(fifo_handle) // 从FIFO中弹出最先压入的数据
|
||||
#define kk_fifo_peek_head(fifo_handle) k_fifo_peek_head(fifo_handle) // 查询FIFO中头部的数据地址
|
||||
#define kk_fifo_peek_tail(fifo_handle) k_fifo_peek_tail(fifo_handle) // 查询FIFO中尾部的数据地址
|
||||
|
||||
#define kk_queue_recv(queue_handle, dst) k_queue_recv(queue_handle, dst) // 接收并复制数据
|
||||
#define kk_queue_send(queue_handle, src) k_queue_send(queue_handle, src) // 复制数据并发送
|
||||
#define kk_queue_alloc(queue_handle) k_queue_alloc(queue_handle) // 申请可用于QUEUE的数据结构
|
||||
#define kk_queue_free(data) k_queue_free(data) // 释放由 kk_queue_alloc() 申请的数据结构
|
||||
#define kk_queue_put(data) k_queue_put(data) // 把数据压入到QUEUE中
|
||||
#define kk_queue_take(queue_handle) k_queue_take(queue_handle) // 从QUEUE中弹出最先压入的数据
|
||||
#define kk_queue_peek_head(queue_handle) k_queue_peek_head(queue_handle) // 查询QUEUE中头部的数据地址
|
||||
#define kk_queue_peek_tail(queue_handle) k_queue_peek_tail(queue_handle) // 查询QUEUE中尾部的数据地址
|
||||
#define kk_queue_get_item_size(queue_handle) k_queue_get_item_size(queue_handle); // 读回 k_queue_create() 中设置的 item_size 的值
|
||||
|
||||
#define kk_pipe_fifo_fill(pipe_handle, data, size) k_pipe_fifo_fill(pipe_handle, data, size) // 把内存数据复制到缓存中(写入缓存),返回实际复制成功的字节数
|
||||
#define kk_pipe_poll_write(pipe_handle, data) k_pipe_poll_write(pipe_handle, data) // 写一个字节到缓存中(写入缓存),返回实际复制成功的字节数
|
||||
#define kk_pipe_fifo_read(pipe_handle, data, size) k_pipe_fifo_read(pipe_handle, data, size) // 从管道中复制数据到内存(从缓存读取),返回实际复制成功的字节数。注:参数 data 值可以为 NULL,此时不复制数据,只释放相应的数据量
|
||||
#define kk_pipe_poll_read(pipe_handle, data) k_pipe_poll_read(pipe_handle, data) // 从缓存复制一个字节到指定地址中,返回 0 表示缓存空
|
||||
|
||||
#define kk_pipe_is_ne(pipe_handle) k_pipe_is_ne(pipe_handle) // 获取管道非空, true 有数据
|
||||
#define kk_pipe_get_valid_size(pipe_handle) k_pipe_get_valid_size(pipe_handle) // 获取管道的数据大小(字节数)
|
||||
#define kk_pipe_get_empty_size(pipe_handle) k_pipe_get_empty_size(pipe_handle) // 获取管道的剩余空间(字节数)
|
||||
|
||||
#define kk_pipe_peek_valid(pipe_handle, dst_data, dst_size) k_pipe_peek_valid(pipe_handle, dst_data, dst_size) // 获取当前已写入的连续的内存信息
|
||||
#define kk_pipe_peek_empty(pipe_handle, dst_data, dst_size) k_pipe_peek_empty(pipe_handle, dst_data, dst_size) // 获取当前空闲的连续的内存信息
|
||||
|
||||
#define kk_get_sys_ticks() k_get_sys_ticks() // 获取当前系统时间
|
||||
#define kk_get_heap_mem() k_get_heap_mem() // 获取初始化时指定的堆内存
|
||||
|
||||
#define kk_disable_interrupt() k_disable_interrupt() // 禁止中断
|
||||
#define kk_enable_interrupt() k_enable_interrupt() // 恢复中断
|
||||
|
||||
#define kk_log_sched() k_log_sched() // 打印当前调度日志
|
||||
|
||||
#if defined(MIX_COMMON)
|
||||
#include "heap.h"
|
||||
#endif
|
||||
|
||||
#define kk_malloc(size) heap_malloc(NULL, size) // 申请内存
|
||||
#define kk_calloc(size) heap_calloc(NULL, size) // 申请内存并置0
|
||||
#define kk_realloc(ptr, size) heap_realloc(NULL, ptr, size) // 重定义已申请的内存大小
|
||||
#define kk_free(ptr) heap_free(NULL, ptr) // 释放内存
|
||||
|
||||
#define kk_heap_is_valid(ptr) heap_is_valid(NULL, ptr) // 获取内存指针是否有效
|
||||
#define kk_heap_block_size(ptr) heap_block_size(ptr) // 已申请内存块的实际占用空间大小(不含所有控制信息)(字节)
|
||||
#define kk_heap_space_size(ptr) heap_space_size(ptr) // 已申请内存块的实际占用空间大小(含所有控制信息)(字节)
|
||||
#define kk_heap_used_size() heap_used_size(NULL) // 获取总已使用空间
|
||||
#define kk_heap_free_size() heap_free_size(NULL) // 获取总空闲空间(包含所有碎片)
|
||||
#define kk_heap_block_max() heap_block_max(NULL) // 获取当前最大的连续空间
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
104
components/system/source/shell/README.md
Executable file
104
components/system/source/shell/README.md
Executable file
@@ -0,0 +1,104 @@
|
||||
[简要](../../../README.md)
|
||||
|
||||
# shell
|
||||
|
||||
> 是一款适合单片机用的简单的 shell 模块,使单片也能像 Linux 一样,具体基本的命令行功能,适用于示例、调试、应用等场合。
|
||||
|
||||
## 快捷键支持
|
||||
- Tap: 补全命令或参数
|
||||
- Up: 查看上一个命令
|
||||
- Down: 查看下一个命令
|
||||
- Home: 光标移到开头位置
|
||||
- End: 光标移到结尾位置
|
||||
- Ctrl+C: 结束程序
|
||||
- Ctrl+D: 删除光标后一个字符或结束程序
|
||||
- Ctrl+L: 清空终端
|
||||
- Ctrl+A: 同 Home
|
||||
- Ctrl+E: 同 End
|
||||
- Ctrl+U: 擦除光标前到行首的全部内容
|
||||
- Ctrl+K: 擦除光标后到行尾的全部内容
|
||||
- Ctrl+W: 擦除光标前的单词
|
||||
- Ctrl+Y: 还原擦除的内容
|
||||
- Ctrl+Right: 光标移动到单词首位
|
||||
- Ctrl+Left: 光标移动到单词结尾
|
||||
|
||||
## 如何使用
|
||||
|
||||
### 移植
|
||||
> 调用 sh_init_vt100() 进行初始化时指定并实现两个对应的接口即可,实际上在 [sh_vt100.c](./sh_vt100.c) 已做好一系列的工作,一般情况下无需再另外实现,除非有多数据接口的需求。
|
||||
|
||||
### 初始化
|
||||
> 在 [sh_t100.c](./sh_vt100.c) 中已通过 _install_shell_vt100() 被初始化,对象 g_uart_handle_vt100 直接可用。
|
||||
|
||||
### 注册命令列表
|
||||
> 所有命令都必须先注册才可生效。
|
||||
|
||||
- 使用宏 SH_REGISTER_CMD 注册
|
||||
> 使用自动初始化的宏注册一个父命令列表。以下摘自 [sc.h](./sh.c) 文件的命令定义部分。
|
||||
```c
|
||||
SH_DEF_SUB_CMD(
|
||||
_cmd_echo_sublist,
|
||||
SH_SETUP_CMD("on", "Enable to feedback the command line", _cmd_echo_on, NULL), //
|
||||
SH_SETUP_CMD("off", "Disable to feedback the command line", _cmd_echo_off, NULL), //
|
||||
);
|
||||
|
||||
SH_DEF_SUB_CMD(
|
||||
_cmd_sh_sublist,
|
||||
SH_SETUP_CMD("echo", "Turn on/off echo through sh_echo()", NULL, _cmd_echo_sublist), //
|
||||
SH_SETUP_CMD("history", "Show history control", _cmd_history, _cmd_history_param), //
|
||||
SH_SETUP_CMD("list-init", "List all auto initialize function\r\n\t* Usage: list-init [filter]", _cmd_print_init_fn, NULL), //
|
||||
SH_SETUP_CMD("list-module", "List all module structure\r\n\t* Usage: list-module [filter]", _cmd_print_module_struct, NULL), //
|
||||
SH_SETUP_CMD("version", "Print the shell version", _cmd_version, NULL), //
|
||||
SH_SETUP_CMD("parse-value", "Parse the value of a string demo", _cmd_parse_test, NULL), //
|
||||
);
|
||||
|
||||
SH_REGISTER_CMD(
|
||||
register_internal_command,
|
||||
SH_SETUP_CMD("sh", "Internal command", NULL, _cmd_sh_sublist), //
|
||||
SH_SETUP_CMD("help", "Print the complete root command", _cmd_print_help, _cmd_print_help_param), //
|
||||
SH_SETUP_CMD("select", "Select parent command", _cmd_select, _cmd_select_param), //
|
||||
SH_SETUP_CMD("exit", "Exit parent command or disconnect", _cmd_exit, NULL), //
|
||||
);
|
||||
```
|
||||
|
||||
- 使用函数接口动态注册
|
||||
- sh_register_cmd(const sh_cmd_reg_t *sh_reg);
|
||||
- sh_register_cmd_hide(const sh_cmd_reg_t *sh_reg);
|
||||
- sh_unregister_cmd(const sh_cmd_reg_t *sh_reg);
|
||||
|
||||
### 设置子命令、命令勾子和补全勾子
|
||||
> 命令勾子和执行补全功能的勾子函数都在命令列表中确定,它们分别位于 SH_SETUP_CMD 的第 3、4 个参数。
|
||||
|
||||
- 命令勾子
|
||||
> 如实例中显示,位于 SH_SETUP_CMD 的第 3 个参数,设置命令勾子。
|
||||
> 如果命令勾子取值为函数地址,则表示这个命令为完整命令,此时第 4 个参数必须是 cp_fn ,并且可设置对补全勾子或者为 NULL;
|
||||
> 如果命令勾子取值为NULL,则表示这个命令为父命令,此时第 4 个参数必须是 sub_cmd ,并且指向另一个由 SH_DEF_SUB_CMD 定义的命令列表;
|
||||
|
||||
### 命令勾子的可用接口
|
||||
- sh_set_prompt()
|
||||
- sh_reset_line()
|
||||
- sh_echo()
|
||||
- sh_parse_value()
|
||||
- sh_merge_param()
|
||||
|
||||
### 补全勾子的可用接口
|
||||
- sh_putstr_quiet()
|
||||
- sh_cmd_info()
|
||||
- sh_completion_cmd()
|
||||
- sh_completion_param()
|
||||
- sh_completion_resource()
|
||||
- sh_get_cp_result()
|
||||
|
||||
### 数据流向
|
||||
- 输入
|
||||
> 任何需要解析的数据由 sh_putc() 或 sh_putstr() 开始, 在内部最终完成解析和回调执行的整个过程;
|
||||
|
||||
- 输出
|
||||
> 命令勾子或补全勾子可使用如下函数回显:
|
||||
- sh_echo()
|
||||
- sh_set_prompt()
|
||||
- sh_reset_line()
|
||||
|
||||
## 参考实例
|
||||
- [heap_shell.c](../../../architecture/common/heap/heap_shell.c)
|
||||
- [fatfs_shell.c](../../../source/components/fs/fatfs_shell.c)
|
||||
3051
components/system/source/shell/sh.c
Executable file
3051
components/system/source/shell/sh.c
Executable file
File diff suppressed because it is too large
Load Diff
400
components/system/source/shell/sh.h
Executable file
400
components/system/source/shell/sh.h
Executable file
@@ -0,0 +1,400 @@
|
||||
/**
|
||||
* @file sh.h
|
||||
* @author LokLiang (lokliang@163.com)
|
||||
* @brief
|
||||
* @version 0.1
|
||||
* @date 2023-03-21
|
||||
*
|
||||
* @copyright Copyright (c) 2023
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SH_H__
|
||||
#define __SH_H__
|
||||
|
||||
#include "sys_init.h"
|
||||
#include "list/pslist.h"
|
||||
|
||||
#define SH_VERSION "0.1"
|
||||
|
||||
#ifndef CONFIG_SH_MAX_LINE_LEN
|
||||
#define CONFIG_SH_MAX_LINE_LEN 512 /* 最大命令长度 */
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SH_USE_STRTOD
|
||||
#define CONFIG_SH_USE_STRTOD 1 /* 允许参数解析工具 sh_parse_value() 解析浮点数 */
|
||||
#endif
|
||||
|
||||
typedef struct sh_obj_def sh_t;
|
||||
|
||||
typedef int (*sh_vprint_fn)(const char *format, va_list va); // 实现发送字符串到终端
|
||||
typedef void (*sh_disconnect_fn)(void); // 实现断开连接
|
||||
|
||||
typedef struct // 兼容接口
|
||||
{
|
||||
void (*set_cursor_hoffset)(sh_t *sh_hdl, int last_pos, int new_pos); // 设置光标水平位置
|
||||
void (*insert_str)(sh_t *sh_hdl, const char *str); // 在光标前插入一个字符串
|
||||
sh_vprint_fn vprint; // 实现发送字符串到终端
|
||||
sh_disconnect_fn disconnect; // 实现断开连接
|
||||
|
||||
void (*clear_line)(sh_t *sh_hdl); // 执行清除一行。值为 NULL 时不启用刷命令行
|
||||
} sh_port_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *arg_str; // 待分析的参数
|
||||
int arg_len; // 待解析的参数长度
|
||||
char match_str[CONFIG_SH_MAX_LINE_LEN / 4 * 4]; // 保存相同的字符部分
|
||||
int list_algin; // 配合 list_fmt ,确定格式中 %-ns 的 n 的值
|
||||
int match_num; // 可打印的列表的条目数
|
||||
int print_count; // 已打印计算
|
||||
} sh_cp_info_t;
|
||||
|
||||
typedef enum __packed
|
||||
{
|
||||
SH_CP_OP_NA, // 未发生任何动作
|
||||
SH_CP_OP_CP, // 执行了自动补全
|
||||
SH_CP_OP_PEND, // 正在列举选项
|
||||
SH_CP_OP_LIST, // 完成了列举选项
|
||||
} sh_cp_op_t;
|
||||
|
||||
typedef struct sh_cmd sh_cmd_t;
|
||||
|
||||
typedef void (*sh_cp_fn)(sh_t *sh_hdl, int argc, const char *argv[], bool flag); // flag: 表示当前输入的最后一个参数是否完整(以空格分开)
|
||||
|
||||
typedef enum
|
||||
{
|
||||
_SH_SUB_TYPE_VOID,
|
||||
_SH_SUB_TYPE_CPFN,
|
||||
_SH_SUB_TYPE_SUB,
|
||||
} sh_fn_type_t;
|
||||
|
||||
typedef struct sh_param
|
||||
{
|
||||
const char *cmd;
|
||||
const char *help;
|
||||
} sh_cp_param_t;
|
||||
|
||||
typedef struct sh_cmd
|
||||
{
|
||||
const char *cmd;
|
||||
const char *help;
|
||||
int (*cmd_func)(sh_t *sh_hdl, int argc, const char *argv[]);
|
||||
union
|
||||
{
|
||||
const void *nul;
|
||||
const sh_cmd_t *sub_cmd;
|
||||
sh_cp_fn cp_fn;
|
||||
} sub_fn;
|
||||
sh_fn_type_t fn_type;
|
||||
} sh_cmd_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
sys_psnode_t *node;
|
||||
const sh_cmd_t *cmd;
|
||||
const char *file;
|
||||
int line;
|
||||
} sh_cmd_reg_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *code;
|
||||
void (*key_func)(sh_t *sh_hdl);
|
||||
} sh_key_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
sys_psnode_t *node;
|
||||
const sh_key_t *key;
|
||||
} sh_key_reg_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
enum
|
||||
{
|
||||
_SH_CMD_STATUS_Bad, // 未找到命令
|
||||
_SH_CMD_STATUS_Success, // 成功找到命令函数
|
||||
_SH_CMD_STATUS_Incomplete, // 命令不完整
|
||||
} err_status;
|
||||
|
||||
int match_count; // 表示有多少段为成功匹配的命令段
|
||||
|
||||
const sh_cmd_reg_t *reg_struct; // 根命令结构的定义地址
|
||||
|
||||
const sh_cmd_t *match_cmd; // 最后一个匹配的命令信息
|
||||
|
||||
} sh_cmd_info_t;
|
||||
|
||||
typedef struct // 字符串值解释结果
|
||||
{
|
||||
enum
|
||||
{
|
||||
_PARSE_TYPE_STRING, // 字符串
|
||||
_PARSE_TYPE_INTEGER, // 带符号整型
|
||||
_PARSE_TYPE_UNSIGNED, // 无符号整型
|
||||
_PARSE_TYPE_FLOAT, // 浮点
|
||||
} type;
|
||||
|
||||
union
|
||||
{
|
||||
const char *val_string; // 指向字符串地址
|
||||
int val_integer; // 带符号整型值
|
||||
unsigned val_unsigned; // 无符号整型值
|
||||
float val_float; // 浮点值
|
||||
} value;
|
||||
|
||||
char *endptr; // 指向结束字符
|
||||
|
||||
} sh_parse_t;
|
||||
|
||||
typedef struct sh_obj_def // 对象内存结构
|
||||
{
|
||||
sh_port_t port;
|
||||
|
||||
sys_psnode_t obj_key_node;
|
||||
sh_key_reg_t obj_key_data;
|
||||
|
||||
sys_psnode_t obj_cmd_node;
|
||||
sh_cmd_reg_t obj_cmd_data;
|
||||
|
||||
const char *prompt; // 提示符
|
||||
|
||||
sys_pslist_t key_list; // 已注册的热键链
|
||||
char key_str[8]; // 已缓存的热键代码
|
||||
uint16_t key_stored; // 已缓存的热键数
|
||||
|
||||
sys_pslist_t cmd_list; // 已注册的仅属于对应的终端可见的根命令链
|
||||
char cmd_line[CONFIG_SH_MAX_LINE_LEN / 4 * 4]; // 当前命令缓存(包括 模块提示、命令行,不包括 提示符)
|
||||
char *cmd_buf; // 当前命令行在 cmd_line[] 中的指针
|
||||
uint16_t cmd_stored; // 当前已缓存字符数(不包括 提示符 和 模块提示)
|
||||
uint16_t cmd_input; // 当前光标位置(0.._MAX_CMD_LEN)
|
||||
uint16_t sync_cursor; // 与当前光标同步的位置
|
||||
int cmd_return; // 指令执行的结果
|
||||
|
||||
const sh_cmd_reg_t *select_reg_struct; // 内部 select 命令
|
||||
const sh_cmd_t *select_cmd; // 内部 select 命令
|
||||
|
||||
char *cmd_history; // 命令的历史记录
|
||||
int history_size; // cmd_history 的长度
|
||||
uint16_t *history_index; // 历史记录信息
|
||||
uint16_t history_index_num; // history_index 的成员数
|
||||
uint16_t history_valid_num; // 已记录的历史命令数
|
||||
uint16_t history_show; // 当前正在显示历史命令。如果在显示历史命令时输入任意有效字符,则 cmd_line[] 将立即被更新
|
||||
|
||||
char *cmd_bank; // 用于保存 sh_ctrl_del_word(), sh_ctrl_del_left(), sh_ctrl_del_right() 删除的内容
|
||||
int bank_size; // cmd_bank 的大小(建议值为 CONFIG_SH_MAX_LINE_LEN )
|
||||
|
||||
sh_cp_info_t *cp_info; // 在允许传递 TAB 键到函数并预执行时暂存信息
|
||||
int cp_match_num; // 记录 sh_completion_resource() 需要保持的信息
|
||||
int cp_list_algin; // 记录 sh_completion_resource() 需要保持的信息
|
||||
uint8_t cp_resource_flag; // 标记执行了 sh_completion_resource()
|
||||
uint8_t tab_press_count; // cp_fn() 执行次数计数
|
||||
uint8_t exec_flag; // 禁止重入关键函数
|
||||
volatile sh_cp_op_t cp_operate; // 保存最后一次自动补全的执行效果
|
||||
|
||||
bool disable_echo; // 关闭回显
|
||||
bool disable_history; // 关闭记录历史(以节约CPU开销)
|
||||
} sh_t;
|
||||
|
||||
#define _SH_DO_CONCAT(X, Y) X##Y
|
||||
#define _SH_CONCAT(X, Y) _SH_DO_CONCAT(X, Y)
|
||||
#define _SH_NAME(NAME) _SH_CONCAT(_SH_CONCAT(_SH_CONCAT(__, NAME), __), __LINE__)
|
||||
#define _SH_GENERIC_SUB(SUB) (__builtin_types_compatible_p(__typeof(SUB), void *) ? _SH_SUB_TYPE_VOID \
|
||||
: __builtin_types_compatible_p(__typeof(SUB), __typeof(_sh_generic_cp_fn)) ? _SH_SUB_TYPE_CPFN \
|
||||
: __builtin_types_compatible_p(__typeof(SUB), sh_cmd_t const[]) ? _SH_SUB_TYPE_SUB \
|
||||
: ~0u)
|
||||
|
||||
/* 定义命令 ------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* @brief 定义执行命令的函数
|
||||
*
|
||||
* @param sh_hdl 由 sh_init_vt100() 初始化,在 sh_putc() 传入入的对象
|
||||
* @param argc 已输入参数的数量
|
||||
* @param argv 已输入参数的指针(字符串)
|
||||
*
|
||||
* @verbatim
|
||||
* @c sh.c
|
||||
* @endverbatim
|
||||
*/
|
||||
#define SH_CMD_FN(NAME) __used static int NAME(sh_t *sh_hdl, int argc, const char *argv[])
|
||||
|
||||
/**
|
||||
* @brief 定义执行自动补全的函数,当收到按键为 TAB 时被调用。
|
||||
*
|
||||
* @param sh_hdl 由 sh_init_vt100() 初始化,在 sh_putc() 传入入的对象
|
||||
* @param argc 已输入参数的数量
|
||||
* @param argv 已输入参数的指针(字符串)
|
||||
* @param flag false 表示最后一个参数正在输入,true 表示最后一个参数已完整输入(光标前一个字符是空格)
|
||||
*
|
||||
* @verbatim
|
||||
* @c sh.c
|
||||
* @endverbatim
|
||||
*/
|
||||
#define SH_CMD_CP_FN(NAME) __used static void NAME(sh_t *sh_hdl, int argc, const char *argv[], bool flag)
|
||||
|
||||
/**
|
||||
* @brief 定义命令列表 SH_REGISTER_CMD 或 SH_DEF_SUB_CMD 中的成员
|
||||
*
|
||||
* @param CMD 命令(字符串,不要有空格)
|
||||
* @param HELP 命令的帮助信息(字符串)
|
||||
* @param FUNC 执行命令对的函数( static int _cmd_func(sh_t *sh_hdl, int argc, const char *argv[]) )。如果即值为 NULL 时,表示有子命令。
|
||||
* @param SUB_NAME
|
||||
* 1. 如果 FUNC 取值为 NULL 时, SUB_NAME 必须指向 SH_DEF_SUB_CMD 定义的子命令列表名;
|
||||
* 2. 如果 FUNC 取值为函数时:
|
||||
* 2.1 SUB_NAME 可为 NULL;
|
||||
* 2.1 SUB_NAME 指向 void (*cp_fn)(sh_t *sh_hdl, int argc, const char *argv[]) 表示按 TAB 键时被执行的函数,用于参数补全。
|
||||
*
|
||||
* @verbatim
|
||||
* @c sh.c
|
||||
* @endverbatim
|
||||
*/
|
||||
#define SH_SETUP_CMD(CMD, HELP, FUNC, SUB) \
|
||||
{ \
|
||||
.cmd = CMD, \
|
||||
.help = HELP, \
|
||||
.cmd_func = FUNC, \
|
||||
.sub_fn = {SUB}, \
|
||||
.fn_type = _SH_GENERIC_SUB(SUB), \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 定义子命令列表(由 SH_SETUP_CMD 中的参数 SUB_NAME 所指向的列表)。
|
||||
*
|
||||
* @param SUB_NAME 子命令列表名。需要与 SH_SETUP_CMD 中的参数 SUB_NAME 的值保持一致
|
||||
*
|
||||
* @verbatim
|
||||
* @c sh.c
|
||||
* @endverbatim
|
||||
*/
|
||||
#define SH_DEF_SUB_CMD(SUB_NAME, ...) \
|
||||
static sh_cmd_t const SUB_NAME[] = { \
|
||||
__VA_ARGS__{0}}
|
||||
|
||||
/**
|
||||
* @brief 定义根命令列表。
|
||||
*
|
||||
* @param NAME 描述自动初始化的函数名。
|
||||
*
|
||||
* @param ... 使用 SH_SETUP_CMD 添加任意数量的根命令的信息。
|
||||
*/
|
||||
#define SH_DEF_CMD(NAME, ...) \
|
||||
static sys_psnode_t _SH_NAME(cmd_node_); \
|
||||
static sh_cmd_t const _SH_NAME(cmd_data_)[] = { \
|
||||
__VA_ARGS__{0}}; \
|
||||
static sh_cmd_reg_t const NAME = { \
|
||||
.node = &_SH_NAME(cmd_node_), \
|
||||
.cmd = _SH_NAME(cmd_data_), \
|
||||
.file = __FILE__, \
|
||||
.line = __LINE__, \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 注册根命令列表。将在初始化阶段被自动执行。
|
||||
*
|
||||
* @param NAME 描述自动初始化的函数名。
|
||||
*
|
||||
* @param ... 使用 SH_SETUP_CMD 添加任意数量的根命令的信息。
|
||||
*
|
||||
* @verbatim
|
||||
* @c sh.c
|
||||
* @endverbatim
|
||||
*/
|
||||
#define SH_REGISTER_CMD(NAME, ...) \
|
||||
SH_DEF_CMD(NAME, __VA_ARGS__); \
|
||||
static int _init_##NAME(void) \
|
||||
{ \
|
||||
return sh_register_cmd(&NAME); \
|
||||
} \
|
||||
INIT_EXPORT_COMPONENT(_init_##NAME)
|
||||
|
||||
SH_CMD_CP_FN(_sh_generic_cp_fn) {}
|
||||
|
||||
/* 注册命令 -------------------------------------------------------------------------- */
|
||||
|
||||
int sh_register_cmd(const sh_cmd_reg_t *sh_reg); // 可用自动初始化宏执行 @ref SH_REGISTER_CMD
|
||||
int sh_register_cmd_hide(const sh_cmd_reg_t *sh_reg); // 可用自动初始化宏执行 @ref SH_REGISTER_CMD
|
||||
int sh_unregister_cmd(const sh_cmd_reg_t *sh_reg); // 取消注册一个根命令
|
||||
|
||||
/* 现成终端协议初始化 ----------------------------------------------------------------- */
|
||||
|
||||
extern sh_t g_uart_handle_vt100; // 内部默认已初始化的句柄
|
||||
|
||||
int sh_init_vt100(sh_t *sh_hdl, sh_vprint_fn vprint, sh_disconnect_fn disconnect); // 初始化一个新的 VT100 的终端对象
|
||||
|
||||
void sh_config_history_mem(sh_t *sh_hdl, void *mem, int size); // 选用:配置用于记录历史的缓存
|
||||
void sh_config_backup_mem(sh_t *sh_hdl, void *mem, int size); // 选用:配置用于保存 sh_ctrl_del_word(), sh_ctrl_del_left(), sh_ctrl_del_right() 删除的内容
|
||||
|
||||
/* 执行过程 --------------------------------------------------------------------------- */
|
||||
|
||||
void sh_putc(sh_t *sh_hdl, char c); // 记录一个字符到内部缓存中并解析和执行
|
||||
void sh_putstr(sh_t *sh_hdl, const char *str); // 同 sh_putc()
|
||||
|
||||
void sh_putstr_quiet(sh_t *sh_hdl, const char *str); // 同 sh_putstr() 但不会回显
|
||||
|
||||
void sh_set_prompt(sh_t *sh_hdl, const char *prompt); // 设置提示符
|
||||
|
||||
void sh_reset_line(sh_t *sh_hdl); // 清除命令接收缓存
|
||||
|
||||
int sh_echo(sh_t *sh_hdl, const char *fmt, ...); // 回显到终端
|
||||
|
||||
sh_parse_t sh_parse_value(const char *str); // 参数工具:解析字符串表示的数值
|
||||
|
||||
int sh_merge_param(char *dst, int len, int argc, const char *argv[]); // 参数工具:以空格为分隔符,合并多个参数
|
||||
|
||||
int sh_get_cmd_result(sh_t *sh_hdl); // 获取上一条有效命令的返回值
|
||||
|
||||
void sh_refresh_line(sh_t *sh_hdl); // 执行刷一次当前命令行显示
|
||||
|
||||
/* cp_fn 应用 ---------------------------------------------------------------------- */
|
||||
|
||||
sh_cmd_info_t sh_cmd_info(sh_t *sh_hdl, int argc, const char *argv[]); // 根据参数,获取完全匹配的命令信息
|
||||
|
||||
sh_cp_op_t sh_completion_cmd(sh_t *sh_hdl, int argc, const char *argv[]); // 根据参数,在已注册命令中查找并自动补全命令
|
||||
|
||||
sh_cp_op_t sh_completion_param(sh_t *sh_hdl, const sh_cp_param_t *param); // 仅在 cp_fn() 中可用,根据当前命令行内容,在给出的参数结构中查找并自动补全参数。参数允许为 NULL
|
||||
|
||||
void sh_completion_resource(sh_t *sh_hdl, const char *arg_str, const char *res_str, const char *help); // 仅在 cp_fn() 中可用,根据当前命令行内容,逐个给出可供查找的提示符。内部将根据所提供的数据自动补全
|
||||
sh_cp_op_t sh_get_cp_result(sh_t *sh_hdl); // 配合 sh_completion_resource() 使用,在下次进入 cp_fn() 时获取前一次自动补全的执行效果
|
||||
|
||||
/* 热键功能同步 ----------------------------------------------------------------------- */
|
||||
|
||||
int sh_register_port(sh_t *sh_hdl, const sh_port_t *port); // 配置终端的控制接口
|
||||
int sh_register_key(sh_t *sh_hdl, const sh_key_reg_t *sh_key); // 注册一组热键
|
||||
int sh_unregister_key(sh_t *sh_hdl, const sh_key_reg_t *sh_key); // 取消注册一组热键
|
||||
int sh_register_key_cmd(sh_t *sh_hdl, const sh_cmd_reg_t *sh_reg); // 注册仅属于对应的终端可见的根命令 @ref SH_REGISTER_CMD
|
||||
int sh_unregister_key_cmd(sh_t *sh_hdl, const sh_cmd_reg_t *sh_reg); // 取消注册仅属于对应的终端可见的根命令
|
||||
|
||||
void sh_ctrl_tab(sh_t *sh_hdl); // 同步热键功能:自动实例/打印命令
|
||||
bool sh_ctrl_enter(sh_t *sh_hdl); // 同步热键功能:执行已缓存到的命令
|
||||
bool sh_ctrl_delete(sh_t *sh_hdl, int n); // 同步热键功能:删除光标的后 n 个字符。返回是否成功
|
||||
bool sh_ctrl_backspace(sh_t *sh_hdl, int n); // 同步热键功能:删除光标的前 n 个字符。返回是否成功
|
||||
bool sh_ctrl_up(sh_t *sh_hdl); // 同步热键功能:查看上一个命令,并更新光标位置记录。返回是否成功
|
||||
bool sh_ctrl_down(sh_t *sh_hdl); // 同步热键功能:查看下一个命令,并更新光标位置记录。返回是否成功
|
||||
void sh_ctrl_left(sh_t *sh_hdl); // 同步热键功能:光标左移,并更新光标位置记录
|
||||
void sh_ctrl_right(sh_t *sh_hdl); // 同步热键功能:光标右移,并更新光标位置记录
|
||||
void sh_ctrl_home(sh_t *sh_hdl); // 同步热键功能:光标移到开头位置,并更新光标位置记录
|
||||
void sh_ctrl_end(sh_t *sh_hdl); // 同步热键功能:光标移到结尾位置,并更新光标位置记录
|
||||
void sh_ctrl_set_cursor(sh_t *sh_hdl, int pos); // 同步热键功能:光标移到指定位置(不包括提示符,起始位置为0),并更新光标位置记录
|
||||
void sh_ctrl_word_head(sh_t *sh_hdl); // 同步热键功能:光标移到当前单词的开头,并更新光标位置记录
|
||||
void sh_ctrl_word_tail(sh_t *sh_hdl); // 同步热键功能:光标移到当前单词的结尾,并更新光标位置记录
|
||||
void sh_ctrl_print_cmd_line(sh_t *sh_hdl); // 同步热键功能:打印一次命令行内容
|
||||
unsigned sh_ctrl_del_word(sh_t *sh_hdl); // 同步热键功能:擦除光标前的单词内容。返回:成功擦除的字符数
|
||||
unsigned sh_ctrl_del_left(sh_t *sh_hdl); // 同步热键功能:擦除光标前到行首的全部内容。返回:成功擦除的字符数
|
||||
unsigned sh_ctrl_del_right(sh_t *sh_hdl); // 同步热键功能:擦除光标后到行尾的全部内容。返回:成功擦除的字符数
|
||||
bool sh_ctrl_undelete(sh_t *sh_hdl); // 同步热键功能:插入 sh_ctrl_del_word(), sh_ctrl_del_left(), sh_ctrl_del_right() 擦除的内容。返回是否成功
|
||||
bool sh_ctrl_is_module(sh_t *sh_hdl); // 同步热键功能:查询当前是否使用了 select 命令进入的模块模式(快捷命令模式)
|
||||
|
||||
void sh_ctrl_set_input_pos(sh_t *sh_hdl, uint16_t input_pos); // 设置当前指针(光标)位置(不包括提示符和模块提示),起始位置为0
|
||||
uint16_t sh_ctrl_get_input_pos(sh_t *sh_hdl); // 获取当前指针(光标)位置(不包括提示符和模块提示),起始位置为0
|
||||
|
||||
uint16_t sh_ctrl_get_line_pos(sh_t *sh_hdl); // 根据当前显示内容(包含回翻的历史记录),获取当前光标位置(提示符+模块提示+命令)
|
||||
uint16_t sh_ctrl_get_line_len(sh_t *sh_hdl); // 根据当前显示内容(包含回翻的历史记录),获取最大光标位置(提示符+模块提示+命令)
|
||||
char sh_ctrl_get_line_char(sh_t *sh_hdl, uint16_t pos); // 获取命令行部分的字符(提示符+模块提示+命令)
|
||||
|
||||
/* 其他 ------------------------------------------------------------------------------- */
|
||||
|
||||
void sh_register_external(sh_vprint_fn out); // 用于显式初始化内部函数
|
||||
|
||||
#endif
|
||||
1521
components/system/source/shell/sh_vset.c
Executable file
1521
components/system/source/shell/sh_vset.c
Executable file
File diff suppressed because it is too large
Load Diff
223
components/system/source/shell/sh_vset.h
Executable file
223
components/system/source/shell/sh_vset.h
Executable file
@@ -0,0 +1,223 @@
|
||||
/**
|
||||
* @file sh_vset.h
|
||||
* @author LokLiang
|
||||
* @brief shell 模块专用,可用于通过命令行中的参数设置变量的基本接口
|
||||
* @version 0.1
|
||||
* @date 2023-09-22
|
||||
*
|
||||
* @copyright Copyright (c) 2023
|
||||
*
|
||||
* 本模块实现解析字符,并根据解析的结果对常见类型的的变量赋值的功能。
|
||||
*
|
||||
* 特性:
|
||||
* - 自动分析设置变量的具体类型
|
||||
* - 对取值范围限制
|
||||
* - 可通过命令行的形式进行设置
|
||||
* - 每增加一项写入接口最低消耗 38 个字节的代码空间
|
||||
*
|
||||
* 使用:
|
||||
* 1. 使用 vset_init() 指定内部的 sh 模块对象
|
||||
* 2. 使用对应的宏作为设置函数,其中:
|
||||
* - @b SET_VAR 用于设置无符号整形、带符号整型、单精度的浮点数和字符串的变量
|
||||
* - @b SET_ENUM 用于设置枚举型的变量,支持 SET_VAR 所支持的全部类型
|
||||
* - @b SET_CP_ENUM 对应 SET_ENUM 所设置的变量的可用自动补全函数
|
||||
* 3. 如果输入的参数为 ? 可用于打印当前的设置范围。
|
||||
* 4. 通过选项设置参数,其中:
|
||||
* - @b PSET_FN 指定一个已定义的 const sh_vset_param_t* 的结构作为选项
|
||||
* - @b PSET_CP 根据一个已定义的 const sh_vset_param_t* 执行自动补选项
|
||||
*
|
||||
* 实例1: 以下这些函数可被 SH_SETUP_CMD 中定义的 FUNC 执行,或者作为 sh_vset_param_t::set_func 的成员
|
||||
* static int _value_set_u8(const char *argv[]) { SET_VAR(&var_u8, 1, 200); }
|
||||
* static int _value_set_s16(const char *argv[]) { SET_VAR(&var_s16, -1000, 1000); }
|
||||
* static int _value_set_float(const char *argv[]) { SET_VAR(&var_float, -1000, var_u8); }
|
||||
* static int _value_set_str(const char *argv[]) { SET_VAR(&var_str, 0, 0); }
|
||||
* static int _value_set_enum(const char *argv[]) { SET_ENUM(&var_s32, "enable=1,disable=0"); }
|
||||
*
|
||||
* 实例2: 实现选项+参数的格式
|
||||
* static sh_vset_param_t const s_param_template[] = {
|
||||
* {"--u8", "该选项的帮助信息", value_set_u8, NULL},
|
||||
* {"--s16", "该选项的帮助信息", value_set_s16, NULL},
|
||||
* {"--float", "该选项的帮助信息", value_set_float, NULL},
|
||||
* {"--str", "该选项的帮助信息", value_set_str, NULL},
|
||||
* {"--enum", "该选项的帮助信息", value_set_enum, "enable=1,disable=0"},
|
||||
* static int _value_set(sh_t *sh_hdl, int argc, const char *argv[]) { PSET_FN(s_param_template); } // 这个函数可作为 SH_SETUP_CMD 中定义的 FUNC
|
||||
* static void _value_cp(sh_t *sh_hdl, int argc, const char *argv[], bool flag) { PSET_CP(s_param_template); } // 这个函数可作为 SH_SETUP_CMD 中定义的 SUB
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SH_VSET_H__
|
||||
#define __SH_VSET_H__
|
||||
|
||||
#include "sys_types.h"
|
||||
#include "sh.h"
|
||||
|
||||
/* 描述支待的待设置变量的具体类型 */
|
||||
typedef enum
|
||||
{
|
||||
__TYPE_ATTR_CHR,
|
||||
__TYPE_ATTR_BOOL,
|
||||
__TYPE_ATTR_U8,
|
||||
__TYPE_ATTR_S8,
|
||||
__TYPE_ATTR_U16,
|
||||
__TYPE_ATTR_S16,
|
||||
__TYPE_ATTR_U32,
|
||||
__TYPE_ATTR_S32,
|
||||
__TYPE_ATTR_U64,
|
||||
__TYPE_ATTR_S64,
|
||||
__TYPE_ATTR_FLOAT,
|
||||
__TYPE_ATTR_DOUBLE,
|
||||
__TYPE_ATTR_STR,
|
||||
__TYPE_ATTR_OTHER,
|
||||
} __type_attr_t;
|
||||
|
||||
/**
|
||||
* @brief vset_cb
|
||||
* 当一个参数的设置值合法,即将被执行设置前回调的函数。当回调退出后才会更新到目标变量中。
|
||||
* @param new_value 指向 sh_vset 内部的新值的栈内存地址。提示:可配合 __typeof() 强制转换为确定的类型。
|
||||
*/
|
||||
typedef void (*vset_cb)(sh_t *sh_hdl, void *new_value);
|
||||
|
||||
/* 待设置变量数据结构 */
|
||||
typedef struct
|
||||
{
|
||||
void *dest;
|
||||
__type_attr_t attr;
|
||||
vset_cb cb;
|
||||
} __vset_param_t;
|
||||
|
||||
#define __GENERIC_ATTR(VAR) (__builtin_types_compatible_p(__typeof(VAR), char) ? __TYPE_ATTR_CHR \
|
||||
: __builtin_types_compatible_p(__typeof(VAR), volatile char) ? __TYPE_ATTR_CHR \
|
||||
: __builtin_types_compatible_p(__typeof(VAR), bool) ? __TYPE_ATTR_BOOL \
|
||||
: __builtin_types_compatible_p(__typeof(VAR), volatile bool) ? __TYPE_ATTR_BOOL \
|
||||
: __builtin_types_compatible_p(__typeof(VAR), uint8_t) ? __TYPE_ATTR_U8 \
|
||||
: __builtin_types_compatible_p(__typeof(VAR), volatile uint8_t) ? __TYPE_ATTR_U8 \
|
||||
: __builtin_types_compatible_p(__typeof(VAR), int8_t) ? __TYPE_ATTR_S8 \
|
||||
: __builtin_types_compatible_p(__typeof(VAR), volatile int8_t) ? __TYPE_ATTR_S8 \
|
||||
: __builtin_types_compatible_p(__typeof(VAR), uint16_t) ? __TYPE_ATTR_U16 \
|
||||
: __builtin_types_compatible_p(__typeof(VAR), volatile uint16_t) ? __TYPE_ATTR_U16 \
|
||||
: __builtin_types_compatible_p(__typeof(VAR), int16_t) ? __TYPE_ATTR_S16 \
|
||||
: __builtin_types_compatible_p(__typeof(VAR), volatile int16_t) ? __TYPE_ATTR_S16 \
|
||||
: __builtin_types_compatible_p(__typeof(VAR), uint32_t) ? __TYPE_ATTR_U32 \
|
||||
: __builtin_types_compatible_p(__typeof(VAR), volatile uint32_t) ? __TYPE_ATTR_U32 \
|
||||
: __builtin_types_compatible_p(__typeof(VAR), int32_t) ? __TYPE_ATTR_S32 \
|
||||
: __builtin_types_compatible_p(__typeof(VAR), volatile int32_t) ? __TYPE_ATTR_S32 \
|
||||
: __builtin_types_compatible_p(__typeof(VAR), uint64_t) ? __TYPE_ATTR_U64 \
|
||||
: __builtin_types_compatible_p(__typeof(VAR), volatile uint64_t) ? __TYPE_ATTR_U64 \
|
||||
: __builtin_types_compatible_p(__typeof(VAR), int64_t) ? __TYPE_ATTR_S64 \
|
||||
: __builtin_types_compatible_p(__typeof(VAR), volatile int64_t) ? __TYPE_ATTR_S64 \
|
||||
: __builtin_types_compatible_p(__typeof(VAR), float) ? __TYPE_ATTR_FLOAT \
|
||||
: __builtin_types_compatible_p(__typeof(VAR), volatile float) ? __TYPE_ATTR_FLOAT \
|
||||
: __builtin_types_compatible_p(__typeof(VAR), double) ? __TYPE_ATTR_DOUBLE \
|
||||
: __builtin_types_compatible_p(__typeof(VAR), volatile double) ? __TYPE_ATTR_DOUBLE \
|
||||
: __builtin_types_compatible_p(__typeof(VAR), char[]) ? __TYPE_ATTR_STR \
|
||||
: __TYPE_ATTR_OTHER)
|
||||
|
||||
typedef int (*vset_var_fn)(const char *argv[]);
|
||||
|
||||
typedef struct // 用于长选项设置的描述结构
|
||||
{
|
||||
const char *option; // 选项,如 "--value"
|
||||
const char *help; // 对该选项的描述
|
||||
vset_var_fn set_func; // 与 option 对应的,使用宏 SET_VAR() 或 SET_ENUM() 设置变量的函数。如果值为 NULL 表示该选项无参数,同时对应的输入参数被保留
|
||||
const char *enum_str; // 仅在类型为 vset_enum_fn 时有效,为对应的选项提供可选的补全参数选项,值为 NULL 或 "" 时默认候选参数为 '?'
|
||||
} sh_vset_param_t;
|
||||
|
||||
int vset_unsigned(const __vset_param_t *param, const char *argv[], unsigned int low, unsigned int high);
|
||||
int vset_integer(const __vset_param_t *param, const char *argv[], signed int low, signed int high);
|
||||
int vset_float(const __vset_param_t *param, const char *argv[], float low, float high);
|
||||
int vset_str(const __vset_param_t *param, const char *argv[], unsigned bufsize);
|
||||
int vset_enum(const __vset_param_t *param, const char *argv[], const char *enum_str);
|
||||
void vset_cp_enum(int argc, bool flag, const char *enum_str);
|
||||
|
||||
int vset_option_set(sh_t *sh_hdl, int *argc, const char *argv[], const sh_vset_param_t *p, unsigned size);
|
||||
bool vset_option_cp(sh_t *sh_hdl, int argc, const char *argv[], bool flag, const sh_vset_param_t *p, unsigned size);
|
||||
|
||||
/* 自动分析并设置变量的值,带设置回调 */
|
||||
#define SET_VAR_CB(NAME, LOW, HIGH, CB) \
|
||||
do \
|
||||
{ \
|
||||
static __vset_param_t const param = { \
|
||||
.dest = NAME, \
|
||||
.attr = __GENERIC_ATTR(*(NAME)), \
|
||||
.cb = CB, \
|
||||
}; \
|
||||
if ( \
|
||||
__GENERIC_ATTR(*(NAME)) == __TYPE_ATTR_U8 || \
|
||||
__GENERIC_ATTR(*(NAME)) == __TYPE_ATTR_U16 || \
|
||||
__GENERIC_ATTR(*(NAME)) == __TYPE_ATTR_U32 || \
|
||||
__GENERIC_ATTR(*(NAME)) == __TYPE_ATTR_U64) \
|
||||
{ \
|
||||
return vset_unsigned(¶m, argv, LOW, HIGH); \
|
||||
} \
|
||||
else if ( \
|
||||
__GENERIC_ATTR(*(NAME)) == __TYPE_ATTR_CHR || \
|
||||
__GENERIC_ATTR(*(NAME)) == __TYPE_ATTR_BOOL || \
|
||||
__GENERIC_ATTR(*(NAME)) == __TYPE_ATTR_S8 || \
|
||||
__GENERIC_ATTR(*(NAME)) == __TYPE_ATTR_S16 || \
|
||||
__GENERIC_ATTR(*(NAME)) == __TYPE_ATTR_S32 || \
|
||||
__GENERIC_ATTR(*(NAME)) == __TYPE_ATTR_S64) \
|
||||
{ \
|
||||
return vset_integer(¶m, argv, LOW, HIGH); \
|
||||
} \
|
||||
else if ( \
|
||||
__GENERIC_ATTR(*(NAME)) == __TYPE_ATTR_FLOAT || \
|
||||
__GENERIC_ATTR(*(NAME)) == __TYPE_ATTR_DOUBLE) \
|
||||
{ \
|
||||
return vset_float(¶m, argv, LOW, HIGH); \
|
||||
} \
|
||||
else if ( \
|
||||
__GENERIC_ATTR(*(NAME)) == __TYPE_ATTR_STR) \
|
||||
{ \
|
||||
return vset_str(¶m, argv, sizeof(*(NAME))); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
return -1; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* 设置数据类型为 枚举型 的变量,带设置回调 */
|
||||
#define SET_ENUM_CB(NAME, ENUM_STR, CB) \
|
||||
do \
|
||||
{ \
|
||||
static __vset_param_t const param = { \
|
||||
.dest = NAME, \
|
||||
.attr = __GENERIC_ATTR(*(NAME)), \
|
||||
.cb = CB, \
|
||||
}; \
|
||||
return vset_enum(¶m, argv, ENUM_STR); \
|
||||
} while (0)
|
||||
|
||||
/* 自动分析并设置变量的值 */
|
||||
#define SET_VAR(NAME, LOW, HIGH) SET_VAR_CB(NAME, LOW, HIGH, NULL)
|
||||
|
||||
/* 设置数据类型为 枚举型 的变量 */
|
||||
#define SET_ENUM(NAME, ENUM_STR) SET_ENUM_CB(NAME, ENUM_STR, NULL)
|
||||
|
||||
/* 对应 SET_VAR 所设置的变量的可用自动补全函数 */
|
||||
#define SET_CP_VAR() \
|
||||
do \
|
||||
{ \
|
||||
if (argc + flag == 1) \
|
||||
{ \
|
||||
sh_completion_resource(sh_hdl, NULL, "? ", NULL); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* 对应 SET_ENUM 所设置的变量的可用自动补全函数 */
|
||||
#define SET_CP_ENUM(ENUM_STR) \
|
||||
do \
|
||||
{ \
|
||||
vset_cp_enum(argc, flag, ENUM_STR); \
|
||||
} while (0)
|
||||
|
||||
#define PSET_FN(OPT) vset_option_set(sh_hdl, &argc, argv, OPT, sizeof(OPT)) /* 作为 SH_CMD_FN() 的实际执行函数 */
|
||||
#define PSET_CP(OPT) vset_option_cp(sh_hdl, argc, argv, flag, OPT, sizeof(OPT)) /* 作为 SH_CMD_CP_FN() 的实际执行函数 */
|
||||
|
||||
typedef void (*vset_global_cb)(sh_t *sh_hdl);
|
||||
|
||||
void vset_init(sh_t *sh_hdl, vset_global_cb cb);
|
||||
|
||||
void vset_force_cb(void);
|
||||
|
||||
#endif
|
||||
455
components/system/source/shell/sh_vt100.c
Executable file
455
components/system/source/shell/sh_vt100.c
Executable file
@@ -0,0 +1,455 @@
|
||||
/**
|
||||
* @file sh_vt100.c
|
||||
* @author LokLiang (lokliang@163.com)
|
||||
* @brief
|
||||
* @version 0.1
|
||||
* @date 2023-03-21
|
||||
*
|
||||
* @copyright Copyright (c) 2023
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sh.h"
|
||||
#include "sh_vt100.h"
|
||||
#include "sys_log.h"
|
||||
|
||||
#ifndef CONFIG_SH_MAX_HISTORY_LEN
|
||||
#define CONFIG_SH_MAX_HISTORY_LEN 255 /* 用于记录命令的缓存长度 */
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief 定义热键列表 SH_DEF_KEY 中的成员
|
||||
*
|
||||
* @param KEY 热键代码(字符串)
|
||||
* @param FUNC 热键对应的函数( static void _key_func(void) )
|
||||
*
|
||||
* @verbatim
|
||||
* @c sh_vt100.c
|
||||
* @endverbatim
|
||||
*/
|
||||
#define SH_SETUP_KEY(KEY, FUNC) \
|
||||
{ \
|
||||
.code = KEY, \
|
||||
.key_func = FUNC, \
|
||||
}
|
||||
|
||||
#define SH_DEF_KEY(NAME, ...) \
|
||||
static sys_psnode_t _SH_NAME(key_node_); \
|
||||
static sh_key_t const _SH_NAME(key_data_)[] = { \
|
||||
__VA_ARGS__{0}}; \
|
||||
static sh_key_reg_t const NAME = { \
|
||||
.node = &_SH_NAME(key_node_), \
|
||||
.key = _SH_NAME(key_data_), \
|
||||
};
|
||||
|
||||
sh_t g_uart_handle_vt100;
|
||||
|
||||
static char last_key = '\0';
|
||||
|
||||
/* 基本键键 */
|
||||
static void _exec_key_TAB(sh_t *sh_hdl); // 补全命令
|
||||
static void _exec_key_ENTER(sh_t *sh_hdl); // 执行命令
|
||||
static void _exec_key_LF(sh_t *sh_hdl); // 执行命令
|
||||
static void _exec_key_BACKSPACE(sh_t *sh_hdl); // 删除光标前一个字符
|
||||
static void _exec_key_CTR_H(sh_t *sh_hdl); // 删除光标前一个字符
|
||||
static void _exec_key_DELETE(sh_t *sh_hdl); // 删除光标后一个字符
|
||||
static void _exec_key_UP(sh_t *sh_hdl); // 查看上一个命令
|
||||
static void _exec_key_DW(sh_t *sh_hdl); // 查看下一个命令
|
||||
static void _exec_key_RIGHT(sh_t *sh_hdl); // 光标右移
|
||||
static void _exec_key_LEFT(sh_t *sh_hdl); // 光标左移
|
||||
static void _exec_key_HOME(sh_t *sh_hdl); // 光标移到行首(提示符除外)
|
||||
static void _exec_key_END(sh_t *sh_hdl); // 光标移到行尾
|
||||
|
||||
/* 其他键键 */
|
||||
static void _exec_key_CTR_C(sh_t *sh_hdl); // 结束程序
|
||||
static void _exec_key_CTR_D(sh_t *sh_hdl); // 删除光标后一个字符或结束程序
|
||||
static void _exec_key_CTR_L(sh_t *sh_hdl); // 清空终端
|
||||
static void _exec_key_CTR_A(sh_t *sh_hdl); // 同 HOME
|
||||
static void _exec_key_CTR_E(sh_t *sh_hdl); // 同 END
|
||||
static void _exec_key_CTR_U(sh_t *sh_hdl); // 擦除光标前到行首的全部内容
|
||||
static void _exec_key_CTR_K(sh_t *sh_hdl); // 擦除光标后到行尾的全部内容
|
||||
static void _exec_key_CTR_W(sh_t *sh_hdl); // 擦除光标前的单词
|
||||
static void _exec_key_CTR_Y(sh_t *sh_hdl); // 还原擦除的内容
|
||||
static void _exec_key_CTR_RIGHT(sh_t *sh_hdl); // 光标移动到单词首位
|
||||
static void _exec_key_CTR_LEFT(sh_t *sh_hdl); // 光标移动到单词结尾
|
||||
|
||||
/* 终端操作 */
|
||||
static void _clear(sh_t *sh_hdl); // 清屏
|
||||
static void _del_line(sh_t *sh_hdl, unsigned len); // 删除当前行
|
||||
static void _set_cursor_hoffset(sh_t *sh_hdl, int last_pos, int new_pos);
|
||||
static void _insert_str(sh_t *sh_hdl, const char *str);
|
||||
|
||||
SH_DEF_KEY(
|
||||
_register_vt100_keys,
|
||||
|
||||
/* 基本 */
|
||||
SH_SETUP_KEY(KEY_TAB, _exec_key_TAB), // 补全命令
|
||||
SH_SETUP_KEY(KEY_CTR_M, _exec_key_ENTER), // 执行命令
|
||||
SH_SETUP_KEY(KEY_CTR_J, _exec_key_LF), // 执行命令
|
||||
SH_SETUP_KEY(KEY_BACKSPACE, _exec_key_BACKSPACE), // 删除光标前一个字符
|
||||
SH_SETUP_KEY(KEY_CTR_H, _exec_key_CTR_H), // 删除光标前一个字符
|
||||
SH_SETUP_KEY(KEY_DELETE, _exec_key_DELETE), // 删除光标后一个字符
|
||||
SH_SETUP_KEY(KEY_UP, _exec_key_UP), // 查看上一个命令
|
||||
SH_SETUP_KEY(KEY_DW, _exec_key_DW), // 查看下一个命令
|
||||
SH_SETUP_KEY(KEY_RIGHT, _exec_key_RIGHT), // 光标右移
|
||||
SH_SETUP_KEY(KEY_LEFT, _exec_key_LEFT), // 光标左移
|
||||
SH_SETUP_KEY(KEY_HOME, _exec_key_HOME), // 光标移到行首(提示符除外)
|
||||
SH_SETUP_KEY(KEY_END, _exec_key_END), // 光标移到行尾
|
||||
|
||||
/* 其他 */
|
||||
SH_SETUP_KEY(KEY_CTR_C, _exec_key_CTR_C), // 结束程序
|
||||
SH_SETUP_KEY(KEY_CTR_D, _exec_key_CTR_D), // 删除光标后一个字符或结束程序
|
||||
SH_SETUP_KEY(KEY_CTR_L, _exec_key_CTR_L), // 清空终端
|
||||
SH_SETUP_KEY(KEY_CTR_A, _exec_key_CTR_A), // 同 HOME
|
||||
SH_SETUP_KEY(KEY_CTR_E, _exec_key_CTR_E), // 同 END
|
||||
SH_SETUP_KEY(KEY_CTR_U, _exec_key_CTR_U), // 擦除光标前到行首的全部内容
|
||||
SH_SETUP_KEY(KEY_CTR_K, _exec_key_CTR_K), // 擦除光标后到行尾的全部内容
|
||||
SH_SETUP_KEY(KEY_CTR_W, _exec_key_CTR_W), // 擦除光标前的单词
|
||||
SH_SETUP_KEY(KEY_CTR_Y, _exec_key_CTR_Y), // 还原擦除的内容
|
||||
SH_SETUP_KEY(KEY_CTR_RIGHT, _exec_key_CTR_RIGHT), // 光标移动到单词首位
|
||||
SH_SETUP_KEY(KEY_CTR_LEFT, _exec_key_CTR_LEFT), // 光标移动到单词结尾
|
||||
);
|
||||
|
||||
static void _exec_key_TAB(sh_t *sh_hdl) // "\x09"
|
||||
{
|
||||
sh_ctrl_tab(sh_hdl); // 自动实例/打印命令
|
||||
}
|
||||
|
||||
static void _exec_key_ENTER(sh_t *sh_hdl) // "\x0D"
|
||||
{
|
||||
sh_echo(sh_hdl, "\r\n");
|
||||
sh_ctrl_enter(sh_hdl); // 执行已缓存到的命令
|
||||
sh_ctrl_print_cmd_line(sh_hdl);
|
||||
last_key = '\r';
|
||||
}
|
||||
|
||||
static void _exec_key_LF(sh_t *sh_hdl) // "\x0A"
|
||||
{
|
||||
if (last_key != '\r')
|
||||
{
|
||||
_exec_key_ENTER(sh_hdl);
|
||||
}
|
||||
last_key = '\n';
|
||||
}
|
||||
|
||||
static void _exec_key_DELETE(sh_t *sh_hdl) // "\e[3~"
|
||||
{
|
||||
if (sh_ctrl_delete(sh_hdl, 1))
|
||||
{
|
||||
/* 删除光标右边一个字符 */
|
||||
sh_echo(sh_hdl, DCH(1));
|
||||
}
|
||||
}
|
||||
|
||||
static void _exec_key_BACKSPACE(sh_t *sh_hdl) // "\x7F"
|
||||
{
|
||||
if (sh_ctrl_backspace(sh_hdl, 1))
|
||||
{
|
||||
/* 删除光标左边一个字符,同时使光标自动左移一位 */
|
||||
sh_echo(sh_hdl, CUB(1));
|
||||
sh_echo(sh_hdl, DCH(1));
|
||||
}
|
||||
}
|
||||
|
||||
static void _exec_key_CTR_H(sh_t *sh_hdl) // "\x8"
|
||||
{
|
||||
if (sh_ctrl_backspace(sh_hdl, 1))
|
||||
{
|
||||
/* 删除光标左边一个字符,同时使光标自动左移一位 */
|
||||
uint16_t line_pos = sh_ctrl_get_line_pos(sh_hdl);
|
||||
uint16_t line_len = sh_ctrl_get_line_len(sh_hdl);
|
||||
|
||||
sh_echo(sh_hdl, "\b");
|
||||
for (int i = 0; i < line_len - line_pos; i++)
|
||||
{
|
||||
sh_echo(sh_hdl, "%c", sh_ctrl_get_line_char(sh_hdl, line_pos + i));
|
||||
}
|
||||
sh_echo(sh_hdl, " ");
|
||||
for (int i = 0; i < line_len - line_pos + 1; i++)
|
||||
{
|
||||
sh_echo(sh_hdl, "\b");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void _exec_key_RIGHT(sh_t *sh_hdl) // "\e[C"
|
||||
{
|
||||
sh_ctrl_right(sh_hdl); // 光标右移
|
||||
}
|
||||
|
||||
static void _exec_key_LEFT(sh_t *sh_hdl) // "\e[D"
|
||||
{
|
||||
sh_ctrl_left(sh_hdl); // 光标左移
|
||||
}
|
||||
|
||||
static void _exec_key_HOME(sh_t *sh_hdl) // "\e[H"
|
||||
{
|
||||
sh_ctrl_home(sh_hdl); // 光标移到开头位置
|
||||
}
|
||||
|
||||
static void _exec_key_END(sh_t *sh_hdl) // "\e[F"
|
||||
{
|
||||
sh_ctrl_end(sh_hdl); // 光标移到结尾位置
|
||||
}
|
||||
|
||||
static void _exec_key_UP(sh_t *sh_hdl) // "\e[A"
|
||||
{
|
||||
int len = sh_ctrl_get_line_len(sh_hdl);
|
||||
if (sh_ctrl_up(sh_hdl)) // 上一个命令
|
||||
{
|
||||
_del_line(sh_hdl, len);
|
||||
sh_ctrl_print_cmd_line(sh_hdl);
|
||||
}
|
||||
}
|
||||
|
||||
static void _exec_key_DW(sh_t *sh_hdl) // "\e[B"
|
||||
{
|
||||
int len = sh_ctrl_get_line_len(sh_hdl);
|
||||
if (sh_ctrl_down(sh_hdl)) // 下一个命令
|
||||
{
|
||||
_del_line(sh_hdl, len);
|
||||
sh_ctrl_print_cmd_line(sh_hdl);
|
||||
}
|
||||
}
|
||||
|
||||
__weak void drv_hal_sys_exit(void)
|
||||
{
|
||||
SYS_LOG_WRN("never define exit function");
|
||||
}
|
||||
static void _exec_key_CTR_C(sh_t *sh_hdl) // "\x03"
|
||||
{
|
||||
sh_echo(sh_hdl, "\r\n");
|
||||
drv_hal_sys_exit();
|
||||
}
|
||||
|
||||
static void _exec_key_CTR_D(sh_t *sh_hdl) // "\x04"
|
||||
{
|
||||
if (sh_ctrl_delete(sh_hdl, 1))
|
||||
{
|
||||
/* 删除光标右边一个字符 */
|
||||
sh_echo(sh_hdl, DCH(1));
|
||||
}
|
||||
else
|
||||
{
|
||||
uint16_t input_pos = sh_ctrl_get_input_pos(sh_hdl);
|
||||
if (input_pos == 0)
|
||||
{
|
||||
if (sh_ctrl_is_module(sh_hdl))
|
||||
{
|
||||
sh_putstr(sh_hdl, "exit\r");
|
||||
}
|
||||
else
|
||||
{
|
||||
drv_hal_sys_exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void _exec_key_CTR_L(sh_t *sh_hdl) // "\x0C"
|
||||
{
|
||||
uint16_t input_pos = sh_ctrl_get_input_pos(sh_hdl);
|
||||
|
||||
_clear(sh_hdl);
|
||||
_del_line(sh_hdl, sh_ctrl_get_line_len(sh_hdl));
|
||||
sh_ctrl_print_cmd_line(sh_hdl);
|
||||
|
||||
sh_ctrl_set_input_pos(sh_hdl, input_pos);
|
||||
}
|
||||
|
||||
static void _exec_key_CTR_A(sh_t *sh_hdl) // "\x01"
|
||||
{
|
||||
sh_ctrl_home(sh_hdl); // 光标移到开头位置
|
||||
}
|
||||
|
||||
static void _exec_key_CTR_E(sh_t *sh_hdl) // "\x05"
|
||||
{
|
||||
sh_ctrl_end(sh_hdl); // 光标移到结尾位置
|
||||
}
|
||||
|
||||
static void _exec_key_CTR_U(sh_t *sh_hdl) // "\x15"
|
||||
{
|
||||
/* 删除光标左边的所有字符 */
|
||||
int n = sh_ctrl_del_left(sh_hdl);
|
||||
if (n)
|
||||
{
|
||||
sh_echo(sh_hdl, CUB(n));
|
||||
sh_echo(sh_hdl, DCH(n));
|
||||
}
|
||||
}
|
||||
|
||||
static void _exec_key_CTR_K(sh_t *sh_hdl) // "\x0B"
|
||||
{
|
||||
/* 删除光标右边的所有字符 */
|
||||
int n = sh_ctrl_del_right(sh_hdl);
|
||||
if (n)
|
||||
{
|
||||
sh_echo(sh_hdl, DCH(n));
|
||||
}
|
||||
}
|
||||
|
||||
static void _exec_key_CTR_W(sh_t *sh_hdl) // "\x17"
|
||||
{
|
||||
int n = sh_ctrl_del_word(sh_hdl);
|
||||
if (n)
|
||||
{
|
||||
/* 删除光标左边 n 个字符,同时使光标自动左移 n 位 */
|
||||
sh_echo(sh_hdl, CUB(n));
|
||||
sh_echo(sh_hdl, DCH(n));
|
||||
}
|
||||
}
|
||||
|
||||
static void _exec_key_CTR_Y(sh_t *sh_hdl) // "\x19"
|
||||
{
|
||||
sh_ctrl_undelete(sh_hdl);
|
||||
}
|
||||
|
||||
static void _exec_key_CTR_RIGHT(sh_t *sh_hdl) // "\e[1;5C"
|
||||
{
|
||||
sh_ctrl_word_tail(sh_hdl);
|
||||
}
|
||||
|
||||
static void _exec_key_CTR_LEFT(sh_t *sh_hdl) // "\e[1;5D"
|
||||
{
|
||||
sh_ctrl_word_head(sh_hdl);
|
||||
}
|
||||
|
||||
static int _cmd_clear(sh_t *sh_hdl, int argc, const char *argv[])
|
||||
{
|
||||
_clear(sh_hdl);
|
||||
return 0;
|
||||
}
|
||||
SH_DEF_CMD(
|
||||
_register_cmd_clear,
|
||||
SH_SETUP_CMD("clear", "Clear the terminal screen", _cmd_clear, NULL), // 清屏
|
||||
);
|
||||
|
||||
#if defined(__linux__)
|
||||
|
||||
static void _clear(sh_t *sh_hdl)
|
||||
{
|
||||
sh_echo(sh_hdl, "\ec");
|
||||
}
|
||||
|
||||
static void _del_line(sh_t *sh_hdl, unsigned len)
|
||||
{
|
||||
sh_echo(sh_hdl, DL(0));
|
||||
}
|
||||
|
||||
static void _set_cursor_hoffset(sh_t *sh_hdl, int last_pos, int new_pos)
|
||||
{
|
||||
/* 设置光标水平位置 */
|
||||
int hoffset = new_pos - last_pos;
|
||||
if (hoffset > 0) // 右移
|
||||
{
|
||||
sh_echo(sh_hdl, CUF(hoffset));
|
||||
}
|
||||
else if (hoffset < 0) // 左移
|
||||
{
|
||||
sh_echo(sh_hdl, CUB(-hoffset));
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static void _clear(sh_t *sh_hdl)
|
||||
{
|
||||
sh_echo(sh_hdl, "\ec");
|
||||
}
|
||||
|
||||
static void _del_line(sh_t *sh_hdl, unsigned len)
|
||||
{
|
||||
sh_echo(sh_hdl, "\r");
|
||||
for (int i = 0; i <= len; i++)
|
||||
{
|
||||
sh_echo(sh_hdl, " ");
|
||||
}
|
||||
sh_echo(sh_hdl, "\r");
|
||||
}
|
||||
|
||||
static void _set_cursor_hoffset(sh_t *sh_hdl, int last_pos, int new_pos)
|
||||
{
|
||||
/* 设置光标水平位置 */
|
||||
if (new_pos > last_pos) // 右移
|
||||
{
|
||||
for (; new_pos > last_pos; last_pos++)
|
||||
{
|
||||
char c = sh_ctrl_get_line_char(sh_hdl, last_pos);
|
||||
sh_echo(sh_hdl, "%c", c);
|
||||
}
|
||||
}
|
||||
else if (new_pos < last_pos) // 左移
|
||||
{
|
||||
for (; new_pos < last_pos; last_pos--)
|
||||
{
|
||||
sh_echo(sh_hdl, "\b");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void _insert_str(sh_t *sh_hdl, const char *str)
|
||||
{
|
||||
sh_echo(sh_hdl, ICH(strlen(str)));
|
||||
sh_echo(sh_hdl, "%s", str);
|
||||
}
|
||||
|
||||
__used static void _clear_line(sh_t *sh_hdl)
|
||||
{
|
||||
_del_line(sh_hdl, sh_ctrl_get_line_len(sh_hdl));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 初始化一个新的 VT100 的终端对象。
|
||||
*
|
||||
* @param sh_hdl 被初始化由 sh_putc() 或 sh_putstr() 的对象
|
||||
* @param vprint 注册实现函数 sh_hdl ==> 终端和显示
|
||||
* @param disconnect 当执行 exit 命令时被回调的,用于断开连接的函数。如不需要可设为 NULL
|
||||
*/
|
||||
int sh_init_vt100(sh_t *sh_hdl, sh_vprint_fn vprint, sh_disconnect_fn disconnect)
|
||||
{
|
||||
int ret = 0;
|
||||
for (int i = 0; i < sizeof(*sh_hdl); i++)
|
||||
{
|
||||
((uint8_t *)sh_hdl)[i] = 0;
|
||||
}
|
||||
|
||||
sh_port_t port = {
|
||||
.set_cursor_hoffset = _set_cursor_hoffset,
|
||||
.insert_str = _insert_str,
|
||||
.vprint = vprint,
|
||||
.disconnect = disconnect,
|
||||
// .clear_line = _clear_line, // 执行清除一行。值为 NULL 时不启用刷命令行
|
||||
};
|
||||
sh_register_port(sh_hdl, &port);
|
||||
|
||||
sh_hdl->cmd_buf = sh_hdl->cmd_line;
|
||||
|
||||
sh_hdl->obj_key_data = _register_vt100_keys;
|
||||
sh_hdl->obj_key_data.node = &sh_hdl->obj_key_node;
|
||||
ret |= sh_register_key(sh_hdl, &sh_hdl->obj_key_data);
|
||||
|
||||
sh_hdl->obj_cmd_data = _register_cmd_clear;
|
||||
sh_hdl->obj_cmd_data.node = &sh_hdl->obj_cmd_node;
|
||||
ret |= sh_register_key_cmd(sh_hdl, &sh_hdl->obj_cmd_data);
|
||||
|
||||
return -!!ret;
|
||||
}
|
||||
|
||||
static int _install_shell_vt100(void)
|
||||
{
|
||||
if (sh_init_vt100(&g_uart_handle_vt100, SYS_VPRINT, NULL) == 0)
|
||||
{
|
||||
static uint8_t history_mem[CONFIG_SH_MAX_HISTORY_LEN];
|
||||
static uint8_t bank_mem[CONFIG_SH_MAX_LINE_LEN];
|
||||
sh_config_history_mem(&g_uart_handle_vt100, history_mem, sizeof(history_mem));
|
||||
sh_config_backup_mem(&g_uart_handle_vt100, bank_mem, sizeof(bank_mem));
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
INIT_EXPORT_COMPONENT(_install_shell_vt100);
|
||||
117
components/system/source/shell/sh_vt100.h
Executable file
117
components/system/source/shell/sh_vt100.h
Executable file
@@ -0,0 +1,117 @@
|
||||
/**
|
||||
* @file sh_vt100.h
|
||||
* @author LokLiang (lokliang@163.com)
|
||||
* @brief
|
||||
* @version 0.1
|
||||
* @date 2023-03-21
|
||||
*
|
||||
* @copyright Copyright (c) 2023
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SH_VT100_h__
|
||||
#define __SH_VT100_h__
|
||||
|
||||
/* 热键 */
|
||||
#define KEY_CTR_A "\x01"
|
||||
#define KEY_CTR_B "\x02"
|
||||
#define KEY_CTR_C "\x03"
|
||||
#define KEY_CTR_D "\x04"
|
||||
#define KEY_CTR_E "\x05"
|
||||
#define KEY_CTR_F "\x06"
|
||||
#define KEY_CTR_G "\x07"
|
||||
#define KEY_CTR_H "\x08"
|
||||
#define KEY_CTR_I "\x09"
|
||||
#define KEY_TAB "\x09"
|
||||
#define KEY_CTR_J "\x0A"
|
||||
#define KEY_CTR_K "\x0B"
|
||||
#define KEY_CTR_L "\x0C"
|
||||
#define KEY_CTR_M "\x0D"
|
||||
#define KEY_CTR_N "\x0E"
|
||||
#define KEY_CTR_O "\x0F"
|
||||
#define KEY_CTR_P "\x10"
|
||||
#define KEY_CTR_Q "\x11"
|
||||
#define KEY_CTR_R "\x12"
|
||||
#define KEY_CTR_S "\x13"
|
||||
#define KEY_CTR_T "\x14"
|
||||
#define KEY_CTR_U "\x15"
|
||||
#define KEY_CTR_V "\x16"
|
||||
#define KEY_CTR_W "\x17"
|
||||
#define KEY_CTR_X "\x18"
|
||||
#define KEY_CTR_Y "\x19"
|
||||
#define KEY_CTR_Z "\x1A"
|
||||
#define KEY_PAUSE "\x1A"
|
||||
#define KEY_ESC "\x1b"
|
||||
#define KEY_BACKSPACE "\x7F"
|
||||
#define KEY_UP "\x1b[A"
|
||||
#define KEY_DW "\x1b[B"
|
||||
#define KEY_RIGHT "\x1b[C"
|
||||
#define KEY_LEFT "\x1b[D"
|
||||
#define KEY_HOME "\x1b[H"
|
||||
#define KEY_END "\x1b[F"
|
||||
#define KEY_CTR_UP "\x1b[1;5A"
|
||||
#define KEY_CTR_DW "\x1b[1;5B"
|
||||
#define KEY_CTR_RIGHT "\x1b[1;5C"
|
||||
#define KEY_CTR_LEFT "\x1b[1;5D"
|
||||
#define KEY_INSERT "\x1b[2~"
|
||||
#define KEY_DELETE "\x1b[3~"
|
||||
#define KEY_PAGE_UP "\x1b[5~"
|
||||
#define KEY_PAGE_DOWN "\x1b[6~"
|
||||
#define KEY_F1 "\x1bOP"
|
||||
#define KEY_F2 "\x1bOQ"
|
||||
#define KEY_F3 "\x1bOR"
|
||||
#define KEY_F4 "\x1bOS"
|
||||
#define KEY_F5 "\x1b[15~"
|
||||
#define KEY_F6 "\x1b[17~"
|
||||
#define KEY_F7 "\x1b[18~"
|
||||
#define KEY_F8 "\x1b[19~"
|
||||
#define KEY_F9 "\x1b[20~"
|
||||
#define KEY_F10 "\x1b[21~"
|
||||
#define KEY_F11 "\x1b[23~"
|
||||
#define KEY_F12 "\x1b[24~"
|
||||
|
||||
|
||||
/*光标操作符*/
|
||||
#define CUU(n) "\x1b[%dA",n /* 光标向上 光标向上 <n> 行 */
|
||||
#define CUD(n) "\x1b[%dB",n /* 光标向下 光标向下 <n> 行 */
|
||||
#define CUF(n) "\x1b[%dC",n /* 光标向前 光标向前(右)<n> 行 */
|
||||
#define CUB(n) "\x1b[%dD",n /* 光标向后 光标向后(左)<n> 行 */
|
||||
#define CNL(n) "\x1b[%dE",n /* 光标下一行 光标从当前位置向下 <n> 行 */
|
||||
#define CPL(n) "\x1b[%dF",n /* 光标当前行 光标从当前位置向上 <n> 行 */
|
||||
#define CHA(n) "\x1b[%dG",n /* 绝对光标水平 光标在当前行中水平移动到第 <n> 个位置 */
|
||||
#define VPA(n) "\x1b[%dd",n /* 绝对垂直行位置 光标在当前列中垂直移动到第 <n> 个位置 */
|
||||
#define CUP(y,x) "\x1b[%d;%dH",y,x /* 光标位置 *光标移动到视区中的 <x>; <y> 坐标,其中 <x> 是 <y> 行的列 */
|
||||
#define HVP(y,x) "\x1b[%d;%df",y,x /* 水平垂直位置 *光标移动到视区中的 <x>; <y> 坐标,其中 <x> 是 <y> 行的列 */
|
||||
|
||||
/*光标可见性*/
|
||||
#define CU_START_BL "\x1b[?12h" /* ATT160 文本光标启用闪烁 开始光标闪烁 */
|
||||
#define CU_STOP_BL "\x1b[?12l" /* ATT160 文本光标禁用闪烁 停止闪烁光标 */
|
||||
#define CU_SHOW "\x1b[?25h" /* DECTCEM 文本光标启用模式显示 显示光标 */
|
||||
#define CU_HIDE "\x1b[?25l" /* DECTCEM 文本光标启用模式隐藏 隐藏光标 */
|
||||
|
||||
/* 字符操作 */
|
||||
#define ICH(n) "\x1b[%d@",n /* 插入字符 在当前光标位置插入 <n> 个空格,这会将所有现有文本移到右侧。 向右溢出屏幕的文本会被删除。*/
|
||||
#define DCH(n) "\x1b[%dP",n /* 删除字符 删除当前光标位置的 <n> 个字符,这会从屏幕右边缘以空格字符移动。*/
|
||||
#define ECH(n) "\x1b[%dX",n /* 擦除字符 擦除当前光标位置的 <n> 个字符,方法是使用空格字符覆盖它们。*/
|
||||
#define IL(n) "\x1b[%dL",n /* 插入行 将 <n> 行插入光标位置的缓冲区。 光标所在的行及其下方的行将向下移动。*/
|
||||
#define DL(n) "\x1b[%dM\r",n /* 删除行 从缓冲区中删除 <n> 行,从光标所在的行开始。*/
|
||||
|
||||
/* 打印字体颜色设置 */
|
||||
#define TX_DEF "\x1b[0m"
|
||||
#define TX_BLACK "\x1b[30m"
|
||||
#define TX_RED "\x1b[31m"
|
||||
#define TX_GREEN "\x1b[32m"
|
||||
#define TX_YELLOW "\x1b[33m"
|
||||
#define TX_BLUE "\x1b[34m"
|
||||
#define TX_WHITE "\x1b[37m"
|
||||
|
||||
/* 打印背景颜色设置 */
|
||||
#define BK_DEF "\x1b[0m"
|
||||
#define BK_BLACK "\x1b[40m"
|
||||
#define BK_RED "\x1b[41m"
|
||||
#define BK_GREEN "\x1b[42m"
|
||||
#define BK_YELLOW "\x1b[43m"
|
||||
#define BK_BLUE "\x1b[44m"
|
||||
#define BK_WHITE "\x1b[47m"
|
||||
|
||||
#endif
|
||||
124
components/system/test/main.c
Executable file
124
components/system/test/main.c
Executable file
@@ -0,0 +1,124 @@
|
||||
#include "os_test.h"
|
||||
#include "sys_init.h"
|
||||
#include "os/os.h"
|
||||
|
||||
#undef SYS_LOG_DOMAIN
|
||||
#define SYS_LOG_DOMAIN "OS"
|
||||
#include "os_util.h"
|
||||
|
||||
#ifndef CONFIG_OS_THREAD_MAIN_STACK_SIZE
|
||||
#define CONFIG_OS_THREAD_MAIN_STACK_SIZE 0x2000
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_OS_THREAD_MAIN_PRIORITY
|
||||
#define CONFIG_OS_THREAD_MAIN_PRIORITY OS_PRIORITY_NORMAL
|
||||
#endif
|
||||
|
||||
static unsigned s_int_nest;
|
||||
|
||||
static unsigned _port_interrupt_save(void)
|
||||
{
|
||||
if (s_int_nest == 0)
|
||||
{
|
||||
os_interrupt_disable();
|
||||
}
|
||||
return s_int_nest++;
|
||||
}
|
||||
|
||||
static void _port_interrupt_restore(unsigned nest)
|
||||
{
|
||||
s_int_nest = nest;
|
||||
if (nest == 0)
|
||||
{
|
||||
os_interrupt_enable();
|
||||
}
|
||||
}
|
||||
|
||||
static k_work_q_t *_port_get_work_q_hdl(void)
|
||||
{
|
||||
struct os_thread_handle *thread_handle = os_thread_get_self();
|
||||
os_work_q_list_t *work_q_list = thread_handle->work_q_list;
|
||||
return &work_q_list->work_q_handle;
|
||||
}
|
||||
|
||||
static void _port_thread_sleep(k_tick_t sleep_ticks)
|
||||
{
|
||||
vTaskDelay(sleep_ticks);
|
||||
}
|
||||
|
||||
static void _work_app_main(void *arg)
|
||||
{
|
||||
}
|
||||
|
||||
static void _os_init(void)
|
||||
{
|
||||
static k_init_t const init_struct = {
|
||||
.malloc = os_malloc,
|
||||
.free = os_free,
|
||||
.get_sys_ticks = os_get_sys_ticks,
|
||||
.interrupt_save = _port_interrupt_save,
|
||||
.interrupt_restore = _port_interrupt_restore,
|
||||
.scheduler_disable = os_scheduler_suspend,
|
||||
.scheduler_enable = os_scheduler_resume,
|
||||
.get_work_q_hdl = _port_get_work_q_hdl,
|
||||
.thread_sleep = _port_thread_sleep,
|
||||
};
|
||||
k_init(&init_struct);
|
||||
|
||||
os_work_q_create(default_os_work_q_hdl,
|
||||
"app-work_q",
|
||||
CONFIG_OS_THREAD_MAIN_STACK_SIZE,
|
||||
CONFIG_OS_THREAD_MAIN_PRIORITY);
|
||||
|
||||
static os_work_t _work_hdl_init;
|
||||
os_work_create(&_work_hdl_init, "work-main", _work_app_main, NULL, 3);
|
||||
os_work_submit(default_os_work_q_hdl, &_work_hdl_init, 0);
|
||||
}
|
||||
|
||||
#include "sh.h"
|
||||
|
||||
static void _work_sh(void *arg)
|
||||
{
|
||||
char c;
|
||||
// while (drv_uart_poll_read(board_uart_cons.id, &c) == 0)
|
||||
// {
|
||||
// sh_putc(&g_uart_handle_vt100, c);
|
||||
// }
|
||||
os_work_later(10);
|
||||
}
|
||||
|
||||
static void _start_shell(void)
|
||||
{
|
||||
static os_work_t work_handler_shell;
|
||||
os_work_create(&work_handler_shell, "work-shell", _work_sh, NULL, 0);
|
||||
os_work_submit(default_os_work_q_hdl, &work_handler_shell, 0);
|
||||
|
||||
sh_putstr_quiet(&g_uart_handle_vt100, "sh version\r");
|
||||
sh_set_prompt(&g_uart_handle_vt100, "sh:/> ");
|
||||
sh_putc(&g_uart_handle_vt100, '\r');
|
||||
}
|
||||
|
||||
void _app_main_handler(void *pArg)
|
||||
{
|
||||
extern int os_test_main(void);
|
||||
os_test_main();
|
||||
}
|
||||
|
||||
int app_main(void)
|
||||
{
|
||||
_os_init();
|
||||
|
||||
_start_shell();
|
||||
|
||||
static os_thread_t s_main_thread;
|
||||
static char *const FirstTaskName = "test_main"; // 首个线程的线程名
|
||||
|
||||
os_thread_create(&s_main_thread,
|
||||
FirstTaskName,
|
||||
_app_main_handler,
|
||||
(void *)rand(),
|
||||
0x1000,
|
||||
1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
11
components/system/test/main.h
Executable file
11
components/system/test/main.h
Executable file
@@ -0,0 +1,11 @@
|
||||
#ifndef __MAIN_H__
|
||||
#define __MAIN_H__
|
||||
|
||||
#include "kk.h"
|
||||
#include "os/os.h"
|
||||
|
||||
void main_k_init(void);
|
||||
void main_timer_reset(void);
|
||||
void main_timer_hook(void (*fn)(void));
|
||||
|
||||
#endif
|
||||
82
components/system/test/os_test.c
Executable file
82
components/system/test/os_test.c
Executable file
@@ -0,0 +1,82 @@
|
||||
#include "os_test.h"
|
||||
#include "sys_init.h"
|
||||
|
||||
Type_OS_TestMem_Def rm_Test; // 用于测试的内存
|
||||
os_work_t test_work_handle[10];
|
||||
os_fifo_t fifo_handle[10];
|
||||
os_queue_t queue_handle[10];
|
||||
os_pipe_t pipe_handle[10];
|
||||
|
||||
os_thread_t *os_test_create_thread(os_thread_t *thread_handle, void (*TaskRoute)(void *), char *name, s16_t Priority)
|
||||
{
|
||||
os_thread_create(thread_handle,
|
||||
name,
|
||||
TaskRoute,
|
||||
0,
|
||||
0x1000,
|
||||
Priority);
|
||||
|
||||
return thread_handle;
|
||||
}
|
||||
//
|
||||
|
||||
/* 具体测试 */
|
||||
extern void os_test_fifo(void);
|
||||
extern void os_test_queue(void);
|
||||
extern void os_test_pipe(void);
|
||||
extern void os_test_yield(uint TestTime);
|
||||
extern void os_test_sem(uint TestTime);
|
||||
extern void os_test_sleep(uint TestTime);
|
||||
|
||||
typedef void (*test_single_t)(void);
|
||||
typedef void (*test_con_t)(uint TestTime);
|
||||
|
||||
static test_con_t const test_tab_rt[] = {
|
||||
os_test_yield,
|
||||
os_test_sem,
|
||||
os_test_sleep,
|
||||
};
|
||||
|
||||
static test_single_t const test_tab_ipc[] = {
|
||||
os_test_fifo,
|
||||
os_test_queue,
|
||||
os_test_pipe,
|
||||
};
|
||||
|
||||
INIT_EXPORT_APP(99)
|
||||
{
|
||||
SYS_LOG_INF("success");
|
||||
os_thread_sleep(200);
|
||||
}
|
||||
|
||||
void os_test_main(void)
|
||||
{
|
||||
rand(); // rand() 用到 malloc()
|
||||
CONS_PRINT("\r\n"); // printf() 用到 _malloc_r()
|
||||
|
||||
SYS_LOG_INF("测试准备中 ... \r\n");
|
||||
|
||||
CONS_PRINT("开始测试...\r\n\r\n");
|
||||
|
||||
for (uint i = 0; i < sizeof(test_tab_rt) / sizeof(test_tab_rt[0]); i++)
|
||||
{
|
||||
test_tab_rt[i](1);
|
||||
CONS_PRINT("\r\n");
|
||||
}
|
||||
|
||||
for (uint i = 0; i < sizeof(test_tab_ipc) / sizeof(test_tab_ipc[0]); i++)
|
||||
{
|
||||
test_tab_ipc[i]();
|
||||
}
|
||||
|
||||
for (uint n = 0; n < sizeof(test_work_handle) / sizeof(test_work_handle[0]); n++)
|
||||
{
|
||||
if (os_work_is_valid(&test_work_handle[n]))
|
||||
{
|
||||
os_work_delete(&test_work_handle[n]);
|
||||
}
|
||||
}
|
||||
|
||||
CONS_PRINT("所有测试结束\r\n");
|
||||
CONS_PRINT("============================\r\n");
|
||||
}
|
||||
68
components/system/test/os_test.h
Executable file
68
components/system/test/os_test.h
Executable file
@@ -0,0 +1,68 @@
|
||||
#ifndef __OS_TEST_H__
|
||||
#define __OS_TEST_H__
|
||||
|
||||
#define CONFIG_SYS_LOG_COLOR_ON 1
|
||||
#undef CONFIG_SYS_LOG_LEVEL
|
||||
#define CONFIG_SYS_LOG_LEVEL SYS_LOG_LEVEL_DBG
|
||||
#include "sys_log.h"
|
||||
|
||||
#include "os/os.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define OSTest_Assert 1
|
||||
|
||||
/* 测试使用到的内存结构 */
|
||||
typedef struct
|
||||
{
|
||||
u8_t UseRate; //记录 CPU 使用率
|
||||
uint CyclePreMS; //计算平均每毫秒运行了任务的循环次数
|
||||
uint StickCount; //累计系统嘀嗒时钟的中断次数
|
||||
uint Error_Line; //调度暂停位置
|
||||
void (*SysTickRoute)(void); //每当产生系统节拍时钟中断时运行的测试函数
|
||||
|
||||
os_mutex_t Mem_Mutex1;
|
||||
os_mutex_t Mem_Mutex2;
|
||||
os_mutex_t Mem_Mutex3;
|
||||
os_mutex_t Mem_Mutex4;
|
||||
|
||||
uint Mutex_Value;
|
||||
|
||||
struct
|
||||
{
|
||||
os_thread_t thread_handle; //任务句柄
|
||||
os_timer_t timer_handle; //任务句柄
|
||||
struct Type_OS_TaskMemDef *AllocMem; //申请到的内存地址
|
||||
uint RunTimes; //任务循环次数
|
||||
uint EventTimes; //
|
||||
uint Stack_Used; //任务最大使用堆栈
|
||||
uint Stack_Empty; //任务最大剩余堆栈
|
||||
vuint Count;
|
||||
double Result_dFPU;
|
||||
volatile float Result_fFPU;
|
||||
} Task[8];
|
||||
|
||||
struct
|
||||
{
|
||||
uint TotalWrite;
|
||||
uint TotalRead;
|
||||
uint WriteLog;
|
||||
uint ReadComp;
|
||||
uint DebugTime1;
|
||||
uint DebugTime2;
|
||||
} BufTest;
|
||||
|
||||
} Type_OS_TestMem_Def;
|
||||
|
||||
extern Type_OS_TestMem_Def rm_Test;
|
||||
|
||||
extern os_work_t test_work_handle[10];
|
||||
extern os_fifo_t fifo_handle[10];
|
||||
extern os_queue_t queue_handle[10];
|
||||
extern os_pipe_t pipe_handle[10];
|
||||
|
||||
/* 用于测试的简便工具 */
|
||||
os_thread_t *os_test_create_thread(os_thread_t *thread_handle, void (*TaskRoute)(void *), char *name, s16_t Priority); //简单创建任务
|
||||
|
||||
#endif
|
||||
//
|
||||
81
components/system/test/os_test_ipc_fifo.c
Executable file
81
components/system/test/os_test_ipc_fifo.c
Executable file
@@ -0,0 +1,81 @@
|
||||
#include "os_test.h"
|
||||
|
||||
static vuint test_flag = 0;
|
||||
|
||||
static void _os_test_fifo_handler_0(void *arg)
|
||||
{
|
||||
SYS_LOG_INF("测试创建和清空, 应出现1个警告");
|
||||
void *first_handle;
|
||||
SYS_ASSERT_FALSE(os_fifo_q_create(&fifo_handle[0]) != OS_OK, "");
|
||||
first_handle = fifo_handle[0].handle;
|
||||
os_fifo_q_clr(&fifo_handle[0]);
|
||||
os_fifo_q_delete(&fifo_handle[0]);
|
||||
|
||||
SYS_LOG_INF("测试警告, 应出现3个警告");
|
||||
SYS_ASSERT_FALSE(os_fifo_q_create(&fifo_handle[0]) != OS_OK, "");
|
||||
uint32_t *p32 = os_fifo_alloc(sizeof(*p32));
|
||||
SYS_ASSERT_FALSE(p32 == 0, "");
|
||||
*p32 = 0x1234abcd;
|
||||
SYS_ASSERT_FALSE(os_fifo_put(&fifo_handle[0], p32) != OS_OK, "");
|
||||
SYS_ASSERT_FALSE(os_fifo_put(&fifo_handle[0], p32) == OS_OK, ""); // os_fifo_put(): fifo_data not valid
|
||||
SYS_ASSERT_FALSE(os_fifo_take(&fifo_handle[0], 0) != p32, "");
|
||||
SYS_ASSERT_FALSE(*p32 != 0x1234abcd, "");
|
||||
SYS_ASSERT_FALSE(os_fifo_take(&fifo_handle[0], 0) != 0, "");
|
||||
SYS_ASSERT_FALSE(os_fifo_free(p32) != OS_OK, "");
|
||||
SYS_ASSERT_FALSE(os_fifo_free(p32) == OS_OK, ""); // os_fifo_free(): 0x.. was not in fifo queue, can not to free
|
||||
SYS_ASSERT_FALSE(os_fifo_put(&fifo_handle[0], p32) == OS_OK, ""); // os_fifo_put(): fifo_data not valid
|
||||
|
||||
SYS_LOG_INF("测试清除");
|
||||
SYS_ASSERT_FALSE(os_fifo_alloc(sizeof(*p32)) != p32, "");
|
||||
SYS_ASSERT_FALSE(os_fifo_put(&fifo_handle[0], p32) != OS_OK, "");
|
||||
os_fifo_q_clr(&fifo_handle[0]);
|
||||
SYS_ASSERT_FALSE(os_fifo_take(&fifo_handle[0], 0) != 0, "");
|
||||
SYS_ASSERT_FALSE(os_fifo_alloc(sizeof(*p32)) != p32, "");
|
||||
SYS_ASSERT_FALSE(os_fifo_free(p32) != OS_OK, "");
|
||||
|
||||
SYS_LOG_INF("测试自动释放已在队列内的数据");
|
||||
SYS_ASSERT_FALSE(os_fifo_alloc(sizeof(*p32)) != p32, "");
|
||||
SYS_ASSERT_FALSE(os_fifo_put(&fifo_handle[0], p32) != 0, "");
|
||||
os_fifo_q_delete(&fifo_handle[0]);
|
||||
SYS_ASSERT_FALSE(os_fifo_q_create(&fifo_handle[0]) != OS_OK, "");
|
||||
SYS_ASSERT_FALSE(first_handle != fifo_handle[0].handle, "");
|
||||
SYS_ASSERT_FALSE(os_fifo_alloc(sizeof(*p32)) != p32, "");
|
||||
SYS_ASSERT_FALSE(os_fifo_put(&fifo_handle[0], p32) != OS_OK, "");
|
||||
os_fifo_q_delete(&fifo_handle[0]);
|
||||
test_flag = 1;
|
||||
}
|
||||
|
||||
static void _os_test_fifo_t1(void *arg)
|
||||
{
|
||||
test_flag = test_flag << 4 | 1;
|
||||
void *mem = os_fifo_take(&fifo_handle[0], -1u);
|
||||
test_flag = test_flag << 4 | 2;
|
||||
os_fifo_free(mem);
|
||||
}
|
||||
|
||||
void os_test_fifo(void)
|
||||
{
|
||||
SYS_LOG_INF("-------------------------------");
|
||||
test_flag = 0;
|
||||
os_work_create(&test_work_handle[0], "", _os_test_fifo_handler_0, NULL, 1);
|
||||
os_work_submit(default_os_work_q_hdl, &test_work_handle[0], 0);
|
||||
os_work_delete(&test_work_handle[0]);
|
||||
SYS_ASSERT_FALSE(test_flag == 0, "");
|
||||
|
||||
SYS_LOG_INF("-------------------------------");
|
||||
size_t max_block_size;
|
||||
os_heap_info(NULL, NULL, &max_block_size);
|
||||
static os_thread_t t1;
|
||||
void *mem;
|
||||
|
||||
SYS_LOG_INF("测试提交 FIFO 唤醒");
|
||||
test_flag = 0;
|
||||
os_fifo_q_create(&fifo_handle[0]);
|
||||
os_test_create_thread(&t1, _os_test_fifo_t1, "t1", OS_PRIORITY_HIGHEST);
|
||||
SYS_ASSERT_FALSE(test_flag != 0x1, "");
|
||||
mem = os_fifo_alloc(0x10);
|
||||
SYS_ASSERT_FALSE(test_flag != 0x1, "");
|
||||
os_fifo_put(&fifo_handle[0], mem);
|
||||
SYS_ASSERT_FALSE(test_flag != 0x12, "");
|
||||
os_fifo_q_delete(&fifo_handle[0]);
|
||||
}
|
||||
57
components/system/test/os_test_ipc_pipe.c
Executable file
57
components/system/test/os_test_ipc_pipe.c
Executable file
@@ -0,0 +1,57 @@
|
||||
#include "os_test.h"
|
||||
|
||||
static vuint test_flag = 0;
|
||||
|
||||
static void _os_test_pipe_handler_0(void *arg)
|
||||
{
|
||||
uint32_t data = 0;
|
||||
uint8_t *p8 = (uint8_t *)&data;
|
||||
SYS_LOG_INF("测试创建和清空, 应出现1个警告");
|
||||
void *first_handle;
|
||||
SYS_ASSERT_FALSE(os_pipe_create(&pipe_handle[0], 4) != OS_OK, "");
|
||||
first_handle = pipe_handle[0].handle;
|
||||
os_pipe_clr(&pipe_handle[0]);
|
||||
os_pipe_delete(&pipe_handle[0]);
|
||||
|
||||
SYS_LOG_INF("测试状态");
|
||||
SYS_ASSERT_FALSE(os_pipe_create(&pipe_handle[0], 3) != OS_OK, "");
|
||||
SYS_ASSERT_FALSE(first_handle != pipe_handle[0].handle, "");
|
||||
SYS_ASSERT_FALSE(os_pipe_is_ne(&pipe_handle[0]) != false, "");
|
||||
SYS_ASSERT_FALSE(os_pipe_get_valid_size(&pipe_handle[0]) != 0, "");
|
||||
SYS_ASSERT_FALSE(os_pipe_get_empty_size(&pipe_handle[0]) != 3, "");
|
||||
|
||||
SYS_LOG_INF("测试写");
|
||||
SYS_ASSERT_FALSE(os_pipe_poll_write(&pipe_handle[0], 1) != 1, "");
|
||||
SYS_ASSERT_FALSE(os_pipe_is_ne(&pipe_handle[0]) != true, "");
|
||||
SYS_ASSERT_FALSE(os_pipe_get_valid_size(&pipe_handle[0]) != 1, "");
|
||||
SYS_ASSERT_FALSE(os_pipe_get_empty_size(&pipe_handle[0]) != 2, "");
|
||||
p8[0] = 2, p8[1] = 3;
|
||||
SYS_ASSERT_FALSE(os_pipe_fifo_fill(&pipe_handle[0], &data, sizeof(data)) != 2, "");
|
||||
SYS_ASSERT_FALSE(os_pipe_get_valid_size(&pipe_handle[0]) != 3, "");
|
||||
SYS_ASSERT_FALSE(os_pipe_get_empty_size(&pipe_handle[0]) != 0, "");
|
||||
|
||||
SYS_LOG_INF("测试读");
|
||||
data = -1u;
|
||||
SYS_ASSERT_FALSE(os_pipe_poll_read(&pipe_handle[0], &p8[0]) != 1, "");
|
||||
SYS_ASSERT_FALSE(os_pipe_is_ne(&pipe_handle[0]) != true, "");
|
||||
SYS_ASSERT_FALSE(os_pipe_get_valid_size(&pipe_handle[0]) != 2, "");
|
||||
SYS_ASSERT_FALSE(os_pipe_get_empty_size(&pipe_handle[0]) != 1, "");
|
||||
SYS_ASSERT_FALSE(os_pipe_fifo_read(&pipe_handle[0], &p8[1], 3) != 2, "");
|
||||
SYS_ASSERT_FALSE(os_pipe_is_ne(&pipe_handle[0]) != false, "");
|
||||
SYS_ASSERT_FALSE(os_pipe_get_valid_size(&pipe_handle[0]) != 0, "");
|
||||
SYS_ASSERT_FALSE(os_pipe_get_empty_size(&pipe_handle[0]) != 3, "");
|
||||
SYS_ASSERT_FALSE(data != 0xff030201, "");
|
||||
|
||||
os_pipe_delete(&pipe_handle[0]);
|
||||
test_flag = 1;
|
||||
}
|
||||
|
||||
void os_test_pipe(void)
|
||||
{
|
||||
SYS_LOG_INF("-------------------------------");
|
||||
test_flag = 0;
|
||||
os_work_create(&test_work_handle[0], "", _os_test_pipe_handler_0, NULL, 1);
|
||||
os_work_submit(default_os_work_q_hdl, &test_work_handle[0], 0);
|
||||
os_work_delete(&test_work_handle[0]);
|
||||
SYS_ASSERT_FALSE(test_flag == 0, "");
|
||||
}
|
||||
47
components/system/test/os_test_ipc_queue.c
Executable file
47
components/system/test/os_test_ipc_queue.c
Executable file
@@ -0,0 +1,47 @@
|
||||
#include "os_test.h"
|
||||
|
||||
static vuint test_flag = 0;
|
||||
|
||||
static void _os_test_queue_t3(void *arg)
|
||||
{
|
||||
uint64_t dst_64 = 0;
|
||||
test_flag = test_flag << 4 | 1;
|
||||
SYS_ASSERT_FALSE(os_queue_recv(&queue_handle[0], &dst_64, OS_WAIT_FOREVER) != OS_OK, "");
|
||||
SYS_ASSERT_FALSE(dst_64 != 0x1234567890abcdef, "");
|
||||
test_flag = test_flag << 4 | 2;
|
||||
}
|
||||
|
||||
void os_test_queue(void)
|
||||
{
|
||||
SYS_LOG_INF("-------------------------------");
|
||||
static os_thread_t t2;
|
||||
uint64_t src_64 = 0x1234567890abcdef;
|
||||
uint64_t dst_64 = 0;
|
||||
int systime_start;
|
||||
int systime_end;
|
||||
os_queue_create(&queue_handle[0], 1, sizeof(src_64));
|
||||
|
||||
SYS_LOG_INF("测试发送和接收");
|
||||
test_flag = 0;
|
||||
os_test_create_thread(&t2, _os_test_queue_t3, "t3", OS_PRIORITY_HIGHEST);
|
||||
SYS_ASSERT_FALSE(test_flag != 0x1, "test_flag = 0x%x", test_flag);
|
||||
SYS_ASSERT_FALSE(os_queue_send(&queue_handle[0], &src_64, 100) != OS_OK, "");
|
||||
SYS_ASSERT_FALSE(test_flag != 0x12, "test_flag = 0x%x", test_flag);
|
||||
|
||||
SYS_LOG_INF("测试发送和发送超时");
|
||||
systime_start = os_get_sys_ticks();
|
||||
SYS_ASSERT_FALSE(os_queue_send(&queue_handle[0], &src_64, 100) != OS_OK, "");
|
||||
SYS_ASSERT_FALSE(os_queue_send(&queue_handle[0], &src_64, 100) == OS_OK, "");
|
||||
systime_end = os_get_sys_ticks();
|
||||
SYS_ASSERT_FALSE(systime_end - systime_start < 100 || systime_end - systime_start > 120, "systime_end - systime_start = %d", systime_end - systime_start);
|
||||
|
||||
SYS_LOG_INF("测试接收和接收超时");
|
||||
systime_start = os_get_sys_ticks();
|
||||
SYS_ASSERT_FALSE(os_queue_recv(&queue_handle[0], &dst_64, 100) != OS_OK, "");
|
||||
SYS_ASSERT_FALSE(dst_64 != src_64, "");
|
||||
SYS_ASSERT_FALSE(os_queue_recv(&queue_handle[0], &dst_64, 100) == OS_OK, "");
|
||||
systime_end = os_get_sys_ticks();
|
||||
SYS_ASSERT_FALSE(systime_end - systime_start < 100 || systime_end - systime_start > 120, "systime_end - systime_start = %d", systime_end - systime_start);
|
||||
|
||||
os_queue_delete(&queue_handle[0]);
|
||||
}
|
||||
46
components/system/test/os_test_sem.c
Executable file
46
components/system/test/os_test_sem.c
Executable file
@@ -0,0 +1,46 @@
|
||||
#include "os_test.h"
|
||||
|
||||
static os_thread_t thread_1;
|
||||
static os_thread_t thread_2;
|
||||
static os_thread_t thread_3;
|
||||
static os_sem_t test_sem_fifo;
|
||||
static vuint test_flag = 0;
|
||||
static void _test_os_t1(void *arg)
|
||||
{
|
||||
os_sem_take(&test_sem_fifo, OS_WAIT_FOREVER);
|
||||
test_flag = test_flag << 4 | 1;
|
||||
os_sem_take(&test_sem_fifo, OS_WAIT_FOREVER);
|
||||
test_flag = test_flag << 4 | 1;
|
||||
}
|
||||
static void _test_os_t2(void *arg)
|
||||
{
|
||||
os_sem_take(&test_sem_fifo, OS_WAIT_FOREVER);
|
||||
test_flag = test_flag << 4 | 2;
|
||||
}
|
||||
static void _test_os_t3(void *arg)
|
||||
{
|
||||
os_sem_take(&test_sem_fifo, OS_WAIT_FOREVER);
|
||||
test_flag = test_flag << 4 | 3;
|
||||
}
|
||||
|
||||
void os_test_sem(uint TestTime)
|
||||
{
|
||||
SYS_LOG_INF("");
|
||||
|
||||
SYS_LOG_DBG("测试 os_sem_create()");
|
||||
SYS_ASSERT_FALSE(os_sem_create(&test_sem_fifo, 1, 3) != OS_OK, "");
|
||||
|
||||
SYS_LOG_DBG("测试 OS_SEM_TYPE_FIFO");
|
||||
test_flag = 0;
|
||||
os_test_create_thread(&thread_1, _test_os_t1, "task01-2", 2);
|
||||
os_test_create_thread(&thread_2, _test_os_t2, "task02-3", 3);
|
||||
os_test_create_thread(&thread_3, _test_os_t3, "task03-4", 4);
|
||||
SYS_ASSERT(test_flag == 0x1, "");
|
||||
|
||||
os_sem_release(&test_sem_fifo);
|
||||
os_sem_release(&test_sem_fifo);
|
||||
os_sem_release(&test_sem_fifo);
|
||||
SYS_ASSERT(test_flag == 0x1321, "test_flag = %#x", test_flag);
|
||||
|
||||
os_sem_delete(&test_sem_fifo);
|
||||
}
|
||||
27
components/system/test/os_test_thread_sleep.c
Executable file
27
components/system/test/os_test_thread_sleep.c
Executable file
@@ -0,0 +1,27 @@
|
||||
#include "os_test.h"
|
||||
|
||||
void os_test_sleep(uint TestTime)
|
||||
{
|
||||
vuint start_tick;
|
||||
vuint test_tick;
|
||||
int offset;
|
||||
|
||||
SYS_LOG_INF("测试延时");
|
||||
|
||||
SYS_LOG_DBG("测试 os_thread_sleep()");
|
||||
os_thread_sleep(1);
|
||||
start_tick = os_get_sys_ticks();
|
||||
os_thread_sleep(10);
|
||||
test_tick = os_get_sys_ticks();
|
||||
offset = test_tick - start_tick;
|
||||
SYS_ASSERT_FALSE(offset != 10 && offset != 11, "offset = %d", offset);
|
||||
|
||||
SYS_LOG_DBG("测试 os_thread_sleep_until()");
|
||||
os_thread_sleep(1);
|
||||
start_tick = os_get_sys_ticks();
|
||||
|
||||
os_thread_sleep(30);
|
||||
test_tick = os_get_sys_ticks();
|
||||
offset = test_tick - start_tick;
|
||||
SYS_ASSERT_FALSE(offset < 30 || offset > 31, "offset = %d", offset); //使用软件测试时允许有1毫秒的误差
|
||||
}
|
||||
110
components/system/test/os_test_thread_yield.c
Executable file
110
components/system/test/os_test_thread_yield.c
Executable file
@@ -0,0 +1,110 @@
|
||||
#include "os_test.h"
|
||||
|
||||
static os_thread_t thread_1;
|
||||
static os_thread_t thread_2;
|
||||
static os_thread_t thread_3;
|
||||
static os_thread_t thread_4;
|
||||
static vuint count1 = 0;
|
||||
static vuint count2 = 0;
|
||||
static vuint count3 = 0;
|
||||
static vuint count4 = 0;
|
||||
|
||||
#define _TEST_TIMES 2000
|
||||
|
||||
static void _test_os_t1(void *arg)
|
||||
{
|
||||
count1 = 0;
|
||||
while (1)
|
||||
{
|
||||
if (count1++ % _TEST_TIMES == 0)
|
||||
{
|
||||
SYS_LOG_DBG("%d", count1 / _TEST_TIMES);
|
||||
if (count1 >= (_TEST_TIMES * 10))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
os_thread_yield();
|
||||
}
|
||||
}
|
||||
static void _test_os_t2(void *arg)
|
||||
{
|
||||
count2 = 0;
|
||||
while (1)
|
||||
{
|
||||
if (count2++ % _TEST_TIMES == 0)
|
||||
{
|
||||
SYS_LOG_DBG("%d", count2 / _TEST_TIMES);
|
||||
if (count2 >= (_TEST_TIMES * 10))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
os_thread_yield();
|
||||
}
|
||||
}
|
||||
|
||||
static void _test_os_t3(void *arg)
|
||||
{
|
||||
count3 = 0;
|
||||
while (1)
|
||||
{
|
||||
if (count3++ % _TEST_TIMES == 0)
|
||||
{
|
||||
SYS_LOG_DBG("%d", count3 / _TEST_TIMES);
|
||||
if (count3 >= (_TEST_TIMES * 10))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
os_thread_suspend(NULL);
|
||||
SYS_ASSERT_FALSE(count3 != count4, "count3 = %d, count4 = %d, suspend fail", count3, count4);
|
||||
}
|
||||
}
|
||||
static void _test_os_t4(void *arg)
|
||||
{
|
||||
count4 = 0;
|
||||
while (1)
|
||||
{
|
||||
if (count4++ % _TEST_TIMES == 0)
|
||||
{
|
||||
SYS_LOG_DBG("%d", count4 / _TEST_TIMES);
|
||||
if (count4 >= (_TEST_TIMES * 10))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
os_thread_resume(&thread_3);
|
||||
SYS_ASSERT_FALSE(count4 + 1 != count3, "count3 = %d, count4 = %d, thread 3 dead!", count3, count4);
|
||||
}
|
||||
}
|
||||
|
||||
void os_test_yield(uint TestTime)
|
||||
{
|
||||
uint start_tick, test_tick, time_nS;
|
||||
SYS_LOG_INF("");
|
||||
|
||||
os_scheduler_suspend();
|
||||
|
||||
os_test_create_thread(&thread_1, _test_os_t1, "task01-4", 4);
|
||||
os_test_create_thread(&thread_2, _test_os_t2, "task02-4", 4);
|
||||
|
||||
start_tick = os_get_sys_ticks();
|
||||
os_scheduler_resume();
|
||||
test_tick = os_get_sys_ticks();
|
||||
time_nS = (test_tick - start_tick) * 1000000 / (count1 + count2);
|
||||
SYS_LOG_DBG("平均时间: %d.%03d uS", time_nS / 1000, time_nS % 1000);
|
||||
|
||||
os_scheduler_suspend();
|
||||
|
||||
os_test_create_thread(&thread_3, _test_os_t3, "task03-3", 3);
|
||||
os_test_create_thread(&thread_4, _test_os_t4, "task04-2", 2);
|
||||
|
||||
start_tick = os_get_sys_ticks();
|
||||
os_scheduler_resume();
|
||||
test_tick = os_get_sys_ticks();
|
||||
time_nS = (test_tick - start_tick) * 1000000 / (count3 + count4);
|
||||
SYS_LOG_DBG("平均时间: %d.%03d uS", time_nS / 1000, time_nS % 1000);
|
||||
|
||||
os_sys_print_info();
|
||||
}
|
||||
47
main/CMakeLists.txt
Normal file
47
main/CMakeLists.txt
Normal file
@@ -0,0 +1,47 @@
|
||||
|
||||
set(srcs-app
|
||||
)
|
||||
|
||||
# 基础程序
|
||||
set(srcs-common
|
||||
"ota.c"
|
||||
"../app/app_main.c"
|
||||
"../app/console.c"
|
||||
"../app/drivers/data_port/sb_data_port.c"
|
||||
"../app/drivers/data_port/uart/uart_port.c"
|
||||
"../app/button/button_event.c"
|
||||
)
|
||||
|
||||
# 自定义框架抽象层
|
||||
set(srcs-components
|
||||
"../components/system/source/k_kit/k_kit.c"
|
||||
"../components/system/source/shell/sh_vt100.c"
|
||||
"../components/system/source/shell/sh_vset.c"
|
||||
"../components/system/source/shell/sh.c"
|
||||
"../sal/esp32s3/kernel/os_heap.c"
|
||||
"../sal/esp32s3/kernel/os_mutex.c"
|
||||
"../sal/esp32s3/kernel/os_hook.c"
|
||||
"../sal/esp32s3/kernel/os_timer.c"
|
||||
"../sal/esp32s3/kernel/os_semaphore.c"
|
||||
"../sal/esp32s3/kernel/os_thread.c"
|
||||
"../sal/esp32s3/kernel/os_kit.c"
|
||||
"../sal/esp32s3/kernel/os_service.c"
|
||||
"../sal/esp32s3/chip/uart_esp32.c"
|
||||
"../sal/esp32s3/soc_shell.c"
|
||||
"../app/config/board_config.c"
|
||||
)
|
||||
set(incs
|
||||
"../app"
|
||||
"../components/system/include"
|
||||
"../components/system/source"
|
||||
"../components/system/source/k_kit"
|
||||
"../components/system/source/shell"
|
||||
"../sal/esp32s3"
|
||||
"../sal/esp32s3/kernel"
|
||||
"${IDF_PATH}/components/freertos/FreeRTOS-Kernel/include/freertos"
|
||||
)
|
||||
|
||||
idf_component_register(SRCS "main.c"
|
||||
${srcs-components}
|
||||
${srcs-common}
|
||||
INCLUDE_DIRS "." ${incs})
|
||||
116
main/main.c
Executable file
116
main/main.c
Executable file
@@ -0,0 +1,116 @@
|
||||
/**
|
||||
* @file main.c
|
||||
* @author LokLiang
|
||||
* @brief 根据实际平台启动并初始化,用户 APP 入口为 void work_app_main(void *arg)
|
||||
* @version 0.1
|
||||
* @date 2023-11-24
|
||||
*
|
||||
* @copyright Copyright (c) 2023
|
||||
*
|
||||
*/
|
||||
|
||||
#include "os/os.h"
|
||||
#include "app_main.h"
|
||||
|
||||
#include "ota.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
#undef SYS_LOG_DOMAIN
|
||||
#define SYS_LOG_DOMAIN "OS"
|
||||
#include "os_util.h"
|
||||
|
||||
#ifndef CONFIG_OS_THREAD_MAIN_STACK_SIZE
|
||||
#define CONFIG_OS_THREAD_MAIN_STACK_SIZE 0x1C00
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_OS_THREAD_MAIN_PRIORITY
|
||||
#define CONFIG_OS_THREAD_MAIN_PRIORITY OS_PRIORITY_NORMAL
|
||||
#endif
|
||||
|
||||
static unsigned s_int_nest;
|
||||
|
||||
static unsigned _port_interrupt_save(void)
|
||||
{
|
||||
if (s_int_nest == 0)
|
||||
{
|
||||
os_interrupt_disable();
|
||||
}
|
||||
return s_int_nest++;
|
||||
}
|
||||
|
||||
static void _port_interrupt_restore(unsigned nest)
|
||||
{
|
||||
s_int_nest = nest;
|
||||
if (nest == 0)
|
||||
{
|
||||
os_interrupt_enable();
|
||||
}
|
||||
}
|
||||
|
||||
static k_work_q_t *_port_get_work_q_hdl(void)
|
||||
{
|
||||
struct os_thread_handle *thread_handle = os_thread_get_self();
|
||||
os_work_q_list_t *work_q_list = thread_handle->work_q_list;
|
||||
return &work_q_list->work_q_handle;
|
||||
}
|
||||
|
||||
static void _port_thread_sleep(k_tick_t sleep_ticks)
|
||||
{
|
||||
vTaskDelay(sleep_ticks);
|
||||
}
|
||||
|
||||
static void _os_init(void)
|
||||
{
|
||||
static k_init_t const init_struct = {
|
||||
.malloc = os_malloc,
|
||||
.free = os_free,
|
||||
.get_sys_ticks = os_get_sys_ticks,
|
||||
.interrupt_save = _port_interrupt_save,
|
||||
.interrupt_restore = _port_interrupt_restore,
|
||||
.scheduler_disable = os_scheduler_suspend,
|
||||
.scheduler_enable = os_scheduler_resume,
|
||||
.get_work_q_hdl = _port_get_work_q_hdl,
|
||||
.thread_sleep = _port_thread_sleep,
|
||||
};
|
||||
k_init(&init_struct);
|
||||
|
||||
os_work_q_create(default_os_work_q_hdl,
|
||||
"app-work_q",
|
||||
CONFIG_OS_THREAD_MAIN_STACK_SIZE,
|
||||
CONFIG_OS_THREAD_MAIN_PRIORITY);
|
||||
|
||||
extern void work_app_main(void *arg);
|
||||
static os_work_t _work_hdl_init;
|
||||
os_work_create(&_work_hdl_init, "work-main", work_app_main, NULL, 3);
|
||||
os_work_submit(default_os_work_q_hdl, &_work_hdl_init, 0);
|
||||
}
|
||||
|
||||
static void _init_prev_nvs(void)
|
||||
{
|
||||
esp_err_t err = nvs_flash_init();
|
||||
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND)
|
||||
{
|
||||
// OTA app partition table has a smaller NVS partition size than the
|
||||
// non-OTA partition table. This size mismatch may cause NVS
|
||||
// initialization to fail. If this happens, we erase NVS partition and
|
||||
// initialize NVS again.
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
err = nvs_flash_init();
|
||||
}
|
||||
ESP_ERROR_CHECK(err);
|
||||
}
|
||||
|
||||
int app_main(void)
|
||||
{
|
||||
/* ota */
|
||||
ota_partition_check();
|
||||
|
||||
/* 初始化平台相关 */
|
||||
_init_prev_nvs();
|
||||
|
||||
/* 初始化 os 抽象层 */
|
||||
_os_init();
|
||||
|
||||
return 0;
|
||||
}
|
||||
75
main/ota.c
Normal file
75
main/ota.c
Normal file
@@ -0,0 +1,75 @@
|
||||
#include "ota.h"
|
||||
|
||||
#include "esp_partition.h"
|
||||
#include "esp_ota_ops.h"
|
||||
#include "esp_flash_partitions.h"
|
||||
|
||||
#define CONFIG_SYS_LOG_LEVEL SYS_LOG_LEVEL_WRN
|
||||
#define SYS_LOG_DOMAIN "OTA"
|
||||
#define CONS_ABORT()
|
||||
#include "sys_log.h"
|
||||
|
||||
#define HASH_LEN 32 /* SHA-256 digest length */
|
||||
static void _print_sha256(const uint8_t *image_hash, const char *label)
|
||||
{
|
||||
char hash_print[HASH_LEN * 2 + 1];
|
||||
hash_print[HASH_LEN * 2] = 0;
|
||||
for (int i = 0; i < HASH_LEN; ++i)
|
||||
{
|
||||
sprintf(&hash_print[i * 2], "%02x", image_hash[i]);
|
||||
}
|
||||
SYS_LOG_INF("%s %s", label, hash_print);
|
||||
}
|
||||
|
||||
void ota_partition_check()
|
||||
{
|
||||
uint8_t sha_256[HASH_LEN] = {0};
|
||||
esp_partition_t partition;
|
||||
|
||||
// get sha256 digest for the partition table
|
||||
partition.address = ESP_PARTITION_TABLE_OFFSET;
|
||||
partition.size = ESP_PARTITION_TABLE_MAX_LEN;
|
||||
partition.type = ESP_PARTITION_TYPE_DATA;
|
||||
esp_partition_get_sha256(&partition, sha_256);
|
||||
_print_sha256(sha_256, "SHA-256 for the partition table:");
|
||||
|
||||
// get sha256 digest for bootloader
|
||||
partition.address = ESP_BOOTLOADER_OFFSET;
|
||||
partition.size = ESP_PARTITION_TABLE_OFFSET;
|
||||
partition.type = ESP_PARTITION_TYPE_APP;
|
||||
esp_partition_get_sha256(&partition, sha_256);
|
||||
_print_sha256(sha_256, "SHA-256 for bootloader: ");
|
||||
|
||||
// get sha256 digest for running partition
|
||||
esp_partition_get_sha256(esp_ota_get_running_partition(), sha_256);
|
||||
_print_sha256(sha_256, "SHA-256 for current firmware: ");
|
||||
|
||||
const esp_partition_t *running = esp_ota_get_running_partition();
|
||||
esp_ota_img_states_t ota_state;
|
||||
if (esp_ota_get_state_partition(running, &ota_state) == ESP_OK)
|
||||
{
|
||||
if (ota_state == ESP_OTA_IMG_PENDING_VERIFY)
|
||||
{
|
||||
// run diagnostic function ...
|
||||
bool diagnostic_is_ok = true; // diagnostic();
|
||||
if (diagnostic_is_ok)
|
||||
{
|
||||
SYS_LOG_INF("Diagnostics completed successfully! Continuing execution ...");
|
||||
esp_ota_mark_app_valid_cancel_rollback();
|
||||
}
|
||||
else
|
||||
{
|
||||
SYS_LOG_ERR("Diagnostics failed! Start rollback to the previous version ...");
|
||||
esp_ota_mark_app_invalid_rollback_and_reboot();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SYS_LOG_INF("");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SYS_LOG_INF("");
|
||||
}
|
||||
}
|
||||
3
main/ota.h
Normal file
3
main/ota.h
Normal file
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
void ota_partition_check(void);
|
||||
9
partitions.csv
Executable file
9
partitions.csv
Executable file
@@ -0,0 +1,9 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap,,,,
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, , 0x5C000,
|
||||
otadata, data, ota, , 0x2000,
|
||||
phy_init, data, phy, , 0x1000,
|
||||
bcfg, 0x40, 0x00, 0x6F000, 0x1000,
|
||||
ota_0, app, ota_0, , 0x1B0000,
|
||||
ota_1, app, ota_1, , 0x1B0000,
|
||||
|
131
sal/esp32s3/chip/uart_esp32.c
Executable file
131
sal/esp32s3/chip/uart_esp32.c
Executable file
@@ -0,0 +1,131 @@
|
||||
#include "drivers/chip/uart.h"
|
||||
|
||||
#include "driver/uart.h"
|
||||
|
||||
#define SYS_LOG_DOMAIN "uart"
|
||||
#include "sys_log.h"
|
||||
|
||||
void drv_uart_pin_configure_txd(hal_id_t id, uint8_t pin)
|
||||
{
|
||||
SYS_LOG_ERR("func not set");
|
||||
}
|
||||
|
||||
void drv_uart_pin_configure_rxd(hal_id_t id, uint8_t pin)
|
||||
{
|
||||
SYS_LOG_ERR("func not set");
|
||||
}
|
||||
|
||||
void drv_uart_enable(hal_id_t id)
|
||||
{
|
||||
SYS_LOG_ERR("func not set");
|
||||
}
|
||||
|
||||
void drv_uart_disable(hal_id_t id)
|
||||
{
|
||||
SYS_LOG_ERR("func not set");
|
||||
}
|
||||
|
||||
void drv_uart_init(hal_id_t id, const uart_param_t *param)
|
||||
{
|
||||
SYS_LOG_ERR("func not set");
|
||||
}
|
||||
|
||||
void drv_uart_deinit(hal_id_t id)
|
||||
{
|
||||
SYS_LOG_ERR("func not set");
|
||||
}
|
||||
|
||||
void drv_uart_set_br(hal_id_t id, unsigned clk, unsigned baudrate)
|
||||
{
|
||||
SYS_LOG_ERR("func not set");
|
||||
}
|
||||
|
||||
unsigned drv_uart_get_br(hal_id_t id, unsigned clk)
|
||||
{
|
||||
SYS_LOG_ERR("func not set");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int drv_uart_poll_read(hal_id_t id, void *data)
|
||||
{
|
||||
return uart_read_bytes(id, data, 1, 0);
|
||||
}
|
||||
|
||||
int drv_uart_poll_write(hal_id_t id, uint8_t data)
|
||||
{
|
||||
SYS_LOG_ERR("func not set");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int drv_uart_fifo_read(hal_id_t id, void *data, int size)
|
||||
{
|
||||
int ret = 0;
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
if (drv_uart_poll_read(id, &((char *)data)[i]) <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
++ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int drv_uart_fifo_fill(hal_id_t id, const void *data, int size)
|
||||
{
|
||||
for (unsigned i = 0; i < size; i++)
|
||||
{
|
||||
if (drv_uart_poll_write(id, ((char *)data)[i]) < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
int drv_uart_irq_callback_enable(hal_id_t id, uart_isr_cb_fn cb)
|
||||
{
|
||||
SYS_LOG_ERR("func not set");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int drv_uart_irq_callback_disable(hal_id_t id)
|
||||
{
|
||||
SYS_LOG_ERR("func not set");
|
||||
return -1;
|
||||
}
|
||||
|
||||
void drv_uart_irq_tx_enable(hal_id_t id, int priority)
|
||||
{
|
||||
SYS_LOG_ERR("func not set");
|
||||
}
|
||||
|
||||
void drv_uart_irq_tx_disable(hal_id_t id)
|
||||
{
|
||||
SYS_LOG_ERR("func not set");
|
||||
}
|
||||
|
||||
void drv_uart_irq_rx_enable(hal_id_t id, int priority)
|
||||
{
|
||||
SYS_LOG_ERR("func not set");
|
||||
}
|
||||
|
||||
void drv_uart_irq_rx_disable(hal_id_t id)
|
||||
{
|
||||
SYS_LOG_ERR("func not set");
|
||||
}
|
||||
|
||||
bool drv_uart_wait_tx_busy(hal_id_t id)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool drv_uart_is_tx_ready(hal_id_t id)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool drv_uart_is_rx_ready(hal_id_t id)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
27
sal/esp32s3/kernel/os_debug.h
Executable file
27
sal/esp32s3/kernel/os_debug.h
Executable file
@@ -0,0 +1,27 @@
|
||||
#ifndef _OS_DEBUG_H_
|
||||
#define _OS_DEBUG_H_
|
||||
|
||||
#undef CONFIG_SYS_LOG_LEVEL
|
||||
#define CONFIG_SYS_LOG_LEVEL SYS_LOG_LEVEL_INF
|
||||
#define SYS_LOG_DOMAIN "OS"
|
||||
#include "sys_log.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#define OS_LOG(FLAG, FMT, ...) _DO_SYS_LOG(FLAG, FMT, ##__VA_ARGS__)
|
||||
#define OS_DBG(FMT, ...) SYS_LOG_DBG(FMT, ##__VA_ARGS__)
|
||||
#define OS_INF(FMT, ...) SYS_LOG_INF(FMT, ##__VA_ARGS__)
|
||||
#define OS_WRN(FMT, ...) SYS_LOG_WRN(FMT, ##__VA_ARGS__)
|
||||
#define OS_ERR(FMT, ...) SYS_LOG_ERR(FMT, ##__VA_ARGS__)
|
||||
|
||||
#define OS_ASS_ISR() SYS_ASSERT(!os_is_isr_context(), "function '%s' exec in ISR contex", __FUNCTION__)
|
||||
#define OS_ASS_HDL(EXP, HANDLE) SYS_ASSERT(EXP, "handle %p", HANDLE)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _OS_DEBUG_H_ */
|
||||
46
sal/esp32s3/kernel/os_heap.c
Executable file
46
sal/esp32s3/kernel/os_heap.c
Executable file
@@ -0,0 +1,46 @@
|
||||
#include "os/os.h"
|
||||
#include "os_util.h"
|
||||
#include "portable.h"
|
||||
#include <string.h>
|
||||
|
||||
void *os_malloc(size_t size)
|
||||
{
|
||||
return pvPortMalloc(size);
|
||||
}
|
||||
|
||||
void *os_calloc(size_t size)
|
||||
{
|
||||
void *ret = os_malloc(size);
|
||||
if (ret)
|
||||
{
|
||||
memset(ret, 0, size);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *os_realloc(void *p, size_t size)
|
||||
{
|
||||
#if (configSTACK_ALLOCATION_FROM_SEPARATE_HEAP == 1)
|
||||
return realloc(p, size);
|
||||
#else
|
||||
OS_DBG("%s() fail @ %d function not support!\r\n", __func__, __LINE__);
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
void os_free(void *p)
|
||||
{
|
||||
vPortFree(p);
|
||||
}
|
||||
|
||||
void os_heap_info(size_t *used_size, size_t *free_size, size_t *max_block_size)
|
||||
{
|
||||
if (max_block_size)
|
||||
{
|
||||
*max_block_size = 0;
|
||||
}
|
||||
if (used_size)
|
||||
*used_size = 0;
|
||||
if (free_size)
|
||||
*free_size = xPortGetFreeHeapSize();
|
||||
}
|
||||
124
sal/esp32s3/kernel/os_hook.c
Executable file
124
sal/esp32s3/kernel/os_hook.c
Executable file
@@ -0,0 +1,124 @@
|
||||
#define SYS_LOG_DOMAIN "OS"
|
||||
#include "os/os.h"
|
||||
#include "sys_log.h"
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
StackType_t uxTimerTaskStack[configTIMER_TASK_STACK_DEPTH];
|
||||
|
||||
void vAssertCalled(void);
|
||||
void vApplicationStackOverflowHook(TaskHandle_t pxTask, char *pcTaskName);
|
||||
void vApplicationMallocFailedHook(void);
|
||||
void vApplicationIdleHook(void);
|
||||
void vApplicationTickHook(void);
|
||||
void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer,
|
||||
StackType_t **ppxTimerTaskStackBuffer,
|
||||
uint32_t *pulTimerTaskStackSize);
|
||||
void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer,
|
||||
StackType_t **ppxIdleTaskStackBuffer,
|
||||
uint32_t *pulIdleTaskStackSize);
|
||||
|
||||
void vAssertCalled(void)
|
||||
{
|
||||
volatile unsigned long looping = 0;
|
||||
|
||||
os_interrupt_disable();
|
||||
{
|
||||
/* Use the debugger to set ul to a non-zero value in order to step out
|
||||
* of this function to determine why it was called. */
|
||||
while (looping == 0LU)
|
||||
{
|
||||
}
|
||||
}
|
||||
os_interrupt_enable();
|
||||
}
|
||||
|
||||
void vApplicationStackOverflowHook(TaskHandle_t pxTask, char *pcTaskName)
|
||||
{
|
||||
SYS_LOG_ERR("task %p(%s) stack over flow\n", pxTask, pcTaskName);
|
||||
/* Run time stack overflow checking is performed if
|
||||
* configCHECK_FOR_STACK_OVERFLOW is defined to 1 or 2. This hook
|
||||
* function is called if a stack overflow is detected. */
|
||||
taskDISABLE_INTERRUPTS();
|
||||
|
||||
for (;;)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
void vApplicationMallocFailedHook(void)
|
||||
{
|
||||
/* Called if a call to pvPortMalloc() fails because there is insufficient
|
||||
* free memory available in the FreeRTOS heap. pvPortMalloc() is called
|
||||
* internally by FreeRTOS API functions that create tasks, queues, software
|
||||
* timers, and semaphores. The size of the FreeRTOS heap is set by the
|
||||
* configTOTAL_HEAP_SIZE configuration constant in FreeRTOSConfig.h. */
|
||||
taskDISABLE_INTERRUPTS();
|
||||
|
||||
for (;;)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
void vApplicationIdleHook(void)
|
||||
{
|
||||
/* This is just a trivial example of an idle hook. It is called on each
|
||||
* cycle of the idle task. It must *NOT* attempt to block. In this case the
|
||||
* idle task just queries the amount of FreeRTOS heap that remains. See the
|
||||
* memory management section on the https://www.FreeRTOS.org web site for memory
|
||||
* management options. If there is a lot of heap memory free then the
|
||||
* configTOTAL_HEAP_SIZE value in FreeRTOSConfig.h can be reduced to free up
|
||||
* RAM. */
|
||||
}
|
||||
|
||||
void vApplicationTickHook(void)
|
||||
{
|
||||
}
|
||||
|
||||
void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer,
|
||||
StackType_t **ppxTimerTaskStackBuffer,
|
||||
uint32_t *pulTimerTaskStackSize)
|
||||
{
|
||||
/* If the buffers to be provided to the Timer task are declared inside this
|
||||
* function then they must be declared static - otherwise they will be allocated on
|
||||
* the stack and so not exists after this function exits. */
|
||||
static StaticTask_t xTimerTaskTCB;
|
||||
|
||||
/* Pass out a pointer to the StaticTask_t structure in which the Timer
|
||||
* task's state will be stored. */
|
||||
*ppxTimerTaskTCBBuffer = &xTimerTaskTCB;
|
||||
|
||||
/* Pass out the array that will be used as the Timer task's stack. */
|
||||
*ppxTimerTaskStackBuffer = uxTimerTaskStack;
|
||||
|
||||
/* Pass out the size of the array pointed to by *ppxTimerTaskStackBuffer.
|
||||
* Note that, as the array is necessarily of type StackType_t,
|
||||
* configMINIMAL_STACK_SIZE is specified in words, not bytes. */
|
||||
*pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
|
||||
}
|
||||
|
||||
/* configUSE_STATIC_ALLOCATION is set to 1, so the application must provide an
|
||||
* implementation of vApplicationGetIdleTaskMemory() to provide the memory that is
|
||||
* used by the Idle task. */
|
||||
void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer,
|
||||
StackType_t **ppxIdleTaskStackBuffer,
|
||||
uint32_t *pulIdleTaskStackSize)
|
||||
{
|
||||
/* If the buffers to be provided to the Idle task are declared inside this
|
||||
* function then they must be declared static - otherwise they will be allocated on
|
||||
* the stack and so not exists after this function exits. */
|
||||
static StaticTask_t xIdleTaskTCB;
|
||||
static StackType_t uxIdleTaskStack[configMINIMAL_STACK_SIZE];
|
||||
|
||||
/* Pass out a pointer to the StaticTask_t structure in which the Idle task's
|
||||
* state will be stored. */
|
||||
*ppxIdleTaskTCBBuffer = &xIdleTaskTCB;
|
||||
|
||||
/* Pass out the array that will be used as the Idle task's stack. */
|
||||
*ppxIdleTaskStackBuffer = uxIdleTaskStack;
|
||||
|
||||
/* Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer.
|
||||
* Note that, as the array is necessarily of type StackType_t,
|
||||
* configMINIMAL_STACK_SIZE is specified in words, not bytes. */
|
||||
*pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
|
||||
}
|
||||
886
sal/esp32s3/kernel/os_kit.c
Executable file
886
sal/esp32s3/kernel/os_kit.c
Executable file
@@ -0,0 +1,886 @@
|
||||
#include "os/os.h"
|
||||
#include "os_util.h"
|
||||
#include "k_kit.h"
|
||||
|
||||
static os_work_q_t s_default_work_q_handle;
|
||||
os_work_q_t *default_os_work_q_hdl = &s_default_work_q_handle;
|
||||
|
||||
static void _os_work_q_thread(void *arg);
|
||||
static void _os_work_q_resume(void *arg);
|
||||
|
||||
static void _os_work_q_thread(void *arg)
|
||||
{
|
||||
os_work_q_list_t *list = arg;
|
||||
for (;;)
|
||||
{
|
||||
k_tick_t tick = k_work_q_handler(&list->work_q_handle);
|
||||
os_sem_take(&list->sem_handle, OS_TicksToMSecs(tick));
|
||||
}
|
||||
}
|
||||
|
||||
static void _os_work_q_resume(void *arg)
|
||||
{
|
||||
os_sem_release(arg);
|
||||
}
|
||||
|
||||
os_state os_work_q_create(os_work_q_t *work_q_handle, // 队列句柄
|
||||
const char *name, // 队列名
|
||||
size_t stack_size, // 栈大小(字节)
|
||||
os_priority priority // 优先级(0 为最低,CONFIG_OS_MAX_PRIORITY 为最高。若输入为负值则表示优先级为 (CONFIG_OS_MAX_PRIORITY + 1 + priority))
|
||||
)
|
||||
{
|
||||
os_work_q_list_t *list = NULL;
|
||||
os_state ret;
|
||||
|
||||
do
|
||||
{
|
||||
if (os_work_q_is_valid(work_q_handle) != false)
|
||||
{
|
||||
OS_WRN("work_q is initialized");
|
||||
ret = OS_FAIL;
|
||||
break;
|
||||
}
|
||||
|
||||
list = os_malloc(sizeof(*list));
|
||||
if (list == NULL)
|
||||
{
|
||||
ret = OS_E_NOMEM;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(list, 0, sizeof(*list));
|
||||
}
|
||||
|
||||
if (k_work_q_create(&list->work_q_handle) != 0)
|
||||
{
|
||||
ret = OS_E_NOMEM;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = os_sem_create(&list->sem_handle, 0, 1);
|
||||
if (ret != OS_OK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
ret = os_thread_create(&list->thread,
|
||||
name,
|
||||
_os_work_q_thread,
|
||||
list,
|
||||
stack_size,
|
||||
priority);
|
||||
if (ret != OS_OK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (work_q_handle)
|
||||
{
|
||||
work_q_handle->handle = list;
|
||||
}
|
||||
|
||||
struct os_thread_handle *thread_handle = list->thread.handle;
|
||||
thread_handle->work_q_list = list;
|
||||
|
||||
k_work_q_resume_regist(&list->work_q_handle, _os_work_q_resume, &list->sem_handle);
|
||||
|
||||
ret = OS_OK;
|
||||
|
||||
} while (0);
|
||||
|
||||
if (ret != OS_OK)
|
||||
{
|
||||
if (list)
|
||||
{
|
||||
if (list->thread.handle)
|
||||
os_thread_delete(&list->thread);
|
||||
if (list->sem_handle.handle)
|
||||
os_sem_delete(&list->sem_handle);
|
||||
if (list->work_q_handle.hdl)
|
||||
k_work_q_delete(&list->work_q_handle);
|
||||
os_free(list);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
os_state os_work_q_delete(os_work_q_t *work_q_handle)
|
||||
{
|
||||
OS_ASS_ISR();
|
||||
|
||||
os_state ret;
|
||||
|
||||
do
|
||||
{
|
||||
if (os_work_q_is_valid(work_q_handle) == false)
|
||||
{
|
||||
OS_WRN("work_q is invalid");
|
||||
ret = OS_FAIL;
|
||||
break;
|
||||
}
|
||||
|
||||
os_scheduler_suspend();
|
||||
|
||||
os_work_q_list_t *list = work_q_handle->handle;
|
||||
if (list)
|
||||
{
|
||||
os_thread_delete(&list->thread);
|
||||
os_sem_delete(&list->sem_handle);
|
||||
k_work_q_delete(&list->work_q_handle);
|
||||
os_free(list);
|
||||
work_q_handle->handle = NULL;
|
||||
ret = OS_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
OS_ERR("err %p", work_q_handle);
|
||||
ret = OS_E_PARAM;
|
||||
}
|
||||
|
||||
os_scheduler_resume();
|
||||
|
||||
} while (0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool os_work_q_is_valid(os_work_q_t *work_q_handle)
|
||||
{
|
||||
bool ret;
|
||||
|
||||
if (work_q_handle == NULL || work_q_handle->handle == NULL)
|
||||
{
|
||||
ret = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = k_work_q_is_valid(work_q_handle->handle);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool os_work_q_delayed_state(os_work_q_t *work_q_handle)
|
||||
{
|
||||
bool ret;
|
||||
|
||||
if (os_work_q_is_valid(work_q_handle) == false)
|
||||
{
|
||||
OS_WRN("work_q is invalid");
|
||||
ret = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = k_work_q_delayed_state(work_q_handle->handle);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool os_work_q_ready_state(os_work_q_t *work_q_handle)
|
||||
{
|
||||
bool ret;
|
||||
|
||||
if (os_work_q_is_valid(work_q_handle) == false)
|
||||
{
|
||||
OS_WRN("work_q is invalid");
|
||||
ret = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = k_work_q_ready_state(work_q_handle->handle);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
os_state os_work_create(os_work_t *work_handle, const char *name, os_work_fn work_route, void *arg, uint8_t sub_prior)
|
||||
{
|
||||
OS_ASS_ISR();
|
||||
k_err_t ret = k_work_create((k_work_t *)work_handle, name, (k_work_fn)work_route, arg, sub_prior);
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
return OS_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return OS_E_NOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
void os_work_delete(os_work_t *work_handle)
|
||||
{
|
||||
OS_ASS_ISR();
|
||||
k_work_delete((k_work_t *)work_handle);
|
||||
}
|
||||
|
||||
bool os_work_is_valid(os_work_t *work_handle)
|
||||
{
|
||||
bool ret = k_work_is_valid((k_work_t *)work_handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool os_work_is_pending(os_work_t *work_handle)
|
||||
{
|
||||
bool ret = k_work_is_pending((k_work_t *)work_handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
os_time_t os_work_time_remain(os_work_t *work_handle)
|
||||
{
|
||||
k_tick_t ret = k_work_time_remain((k_work_t *)work_handle);
|
||||
return os_calc_ticks_to_msec(ret);
|
||||
}
|
||||
|
||||
void os_work_submit(os_work_q_t *work_q_handle, os_work_t *work_handle, os_time_t delay_ms)
|
||||
{
|
||||
if (os_work_q_is_valid(work_q_handle) == false)
|
||||
{
|
||||
OS_WRN("work_q is invalid");
|
||||
}
|
||||
else
|
||||
{
|
||||
k_work_submit(work_q_handle->handle, (k_work_t *)work_handle, os_calc_msec_to_ticks(delay_ms));
|
||||
}
|
||||
}
|
||||
|
||||
void os_work_resume(os_work_t *work_handle, os_time_t delay_ms)
|
||||
{
|
||||
k_work_resume((k_work_t *)work_handle, os_calc_msec_to_ticks(delay_ms));
|
||||
}
|
||||
|
||||
void os_work_suspend(os_work_t *work_handle)
|
||||
{
|
||||
k_work_suspend((k_work_t *)work_handle);
|
||||
}
|
||||
|
||||
void os_work_yield(os_time_t ms)
|
||||
{
|
||||
k_work_yield(os_calc_msec_to_ticks(ms));
|
||||
}
|
||||
|
||||
void os_work_sleep(os_time_t ms)
|
||||
{
|
||||
k_work_sleep(os_calc_msec_to_ticks(ms));
|
||||
}
|
||||
|
||||
void os_work_later(os_time_t ms)
|
||||
{
|
||||
k_work_later(os_calc_msec_to_ticks(ms));
|
||||
}
|
||||
|
||||
void os_work_later_until(os_time_t ms)
|
||||
{
|
||||
k_work_later_until(os_calc_msec_to_ticks(ms));
|
||||
}
|
||||
|
||||
#include "os/os.h"
|
||||
#include "os_util.h"
|
||||
|
||||
#include "k_kit.h"
|
||||
#include "os/os_semaphore.h"
|
||||
#include "queue.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
static void *_os_wait_memory(void *(*fn)(void *func_handle, va_list arp), void *func_handle, os_sem_t *sem, os_time_t wait_ms, ...);
|
||||
static void *_os_ipc_fifo_take(void *fifo_handle, va_list arp);
|
||||
static void *_os_ipc_queue_recv(void *queue_handle, va_list arp);
|
||||
static void *_os_ipc_queue_send(void *queue_handle, va_list arp);
|
||||
static void *_os_ipc_queue_alloc(void *queue_handle, va_list arp);
|
||||
static void *_os_ipc_queue_take(void *queue_handle, va_list arp);
|
||||
|
||||
struct os_fifo_q_handle
|
||||
{
|
||||
k_fifo_t handle;
|
||||
os_sem_t sem_take;
|
||||
};
|
||||
|
||||
os_state os_fifo_q_create(os_fifo_t *fifo_handle)
|
||||
{
|
||||
os_state ret;
|
||||
|
||||
do
|
||||
{
|
||||
struct os_fifo_q_handle *fifo = os_malloc(sizeof(*fifo));
|
||||
if (fifo == NULL)
|
||||
{
|
||||
fifo_handle->handle = NULL;
|
||||
ret = OS_E_NOMEM;
|
||||
break;
|
||||
}
|
||||
|
||||
memset(fifo, 0, sizeof(*fifo));
|
||||
|
||||
if (k_fifo_q_create(&fifo->handle) != 0)
|
||||
{
|
||||
os_free(fifo);
|
||||
ret = OS_E_NOMEM;
|
||||
break;
|
||||
}
|
||||
|
||||
os_sem_create(&fifo->sem_take, 0, 1);
|
||||
fifo_handle->handle = fifo;
|
||||
|
||||
ret = OS_OK;
|
||||
|
||||
} while (0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
os_state os_fifo_q_delete(os_fifo_t *fifo_handle)
|
||||
{
|
||||
OS_ASS_HDL(os_fifo_q_is_valid(fifo_handle), fifo_handle->handle);
|
||||
|
||||
struct os_fifo_q_handle *fifo = fifo_handle->handle;
|
||||
|
||||
os_scheduler_suspend();
|
||||
os_sem_delete(&fifo->sem_take);
|
||||
k_fifo_q_delete(&fifo->handle);
|
||||
os_free(fifo);
|
||||
fifo_handle->handle = NULL;
|
||||
os_scheduler_resume();
|
||||
|
||||
return OS_OK;
|
||||
}
|
||||
|
||||
os_state os_fifo_q_clr(os_fifo_t *fifo_handle)
|
||||
{
|
||||
OS_ASS_HDL(os_fifo_q_is_valid(fifo_handle), fifo_handle->handle);
|
||||
|
||||
struct os_fifo_q_handle *fifo = fifo_handle->handle;
|
||||
k_fifo_q_clr(&fifo->handle);
|
||||
|
||||
return OS_OK;
|
||||
}
|
||||
|
||||
static void *_os_wait_memory(void *(*fn)(void *func_handle, va_list arp), void *func_handle, os_sem_t *sem, os_time_t wait_ms, ...)
|
||||
{
|
||||
va_list arp;
|
||||
va_start(arp, wait_ms);
|
||||
void *ret = fn(func_handle, arp);
|
||||
va_end(arp);
|
||||
|
||||
if (ret == NULL && os_scheduler_is_running() != false && !os_is_isr_context())
|
||||
{
|
||||
TickType_t wait_ticks = os_calc_msec_to_ticks(wait_ms);
|
||||
int wakeup_tick = os_get_sys_ticks() + wait_ticks;
|
||||
|
||||
if (wait_ms)
|
||||
{
|
||||
while (wait_ticks == portMAX_DELAY || (int)(wakeup_tick - os_get_sys_ticks()) > 0)
|
||||
{
|
||||
os_sem_take(sem, wait_ms);
|
||||
|
||||
va_start(arp, wait_ms);
|
||||
ret = fn(func_handle, arp);
|
||||
va_end(arp);
|
||||
|
||||
if (ret)
|
||||
{
|
||||
os_sem_release(sem);
|
||||
break;
|
||||
}
|
||||
|
||||
wait_ms = wakeup_tick - os_get_sys_ticks();
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == NULL)
|
||||
{
|
||||
OS_DBG("waiting semaphore %p timeout", sem);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void os_fifo_q_regist(os_fifo_t *fifo_handle, os_work_t *work_handle, int delay_ticks)
|
||||
{
|
||||
struct os_fifo_q_handle *fifo = fifo_handle->handle;
|
||||
k_fifo_q_regist(&fifo->handle, (k_work_t *)work_handle, delay_ticks);
|
||||
}
|
||||
|
||||
void os_fifo_q_unregist(os_fifo_t *fifo_handle)
|
||||
{
|
||||
struct os_fifo_q_handle *fifo = fifo_handle->handle;
|
||||
k_fifo_q_unregist(&fifo->handle);
|
||||
}
|
||||
|
||||
void *os_fifo_alloc(size_t size)
|
||||
{
|
||||
OS_ASS_ISR();
|
||||
return k_fifo_alloc(size);
|
||||
}
|
||||
|
||||
os_state os_fifo_free(void *fifo_data)
|
||||
{
|
||||
os_state ret;
|
||||
if (k_fifo_free(fifo_data) == 0)
|
||||
{
|
||||
ret = OS_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = OS_E_PARAM;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
os_state os_fifo_put(os_fifo_t *fifo_handle, void *fifo_data)
|
||||
{
|
||||
OS_ASS_HDL(os_fifo_q_is_valid(fifo_handle), fifo_handle->handle);
|
||||
|
||||
struct os_fifo_q_handle *fifo = fifo_handle->handle;
|
||||
os_state ret;
|
||||
|
||||
if (k_fifo_put(&fifo->handle, fifo_data) == 0)
|
||||
{
|
||||
os_sem_release(&fifo->sem_take);
|
||||
ret = OS_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = OS_E_PARAM;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void *_os_ipc_fifo_take(void *fifo_handle, va_list arp)
|
||||
{
|
||||
return k_fifo_take(fifo_handle);
|
||||
}
|
||||
|
||||
void *os_fifo_take(os_fifo_t *fifo_handle, os_time_t wait_ms)
|
||||
{
|
||||
OS_ASS_HDL(os_fifo_q_is_valid(fifo_handle), fifo_handle->handle);
|
||||
|
||||
struct os_fifo_q_handle *fifo = fifo_handle->handle;
|
||||
void *ret = _os_wait_memory(_os_ipc_fifo_take, &fifo->handle, &fifo->sem_take, wait_ms);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *os_fifo_peek_head(os_fifo_t *fifo_handle)
|
||||
{
|
||||
OS_ASS_HDL(os_fifo_q_is_valid(fifo_handle), fifo_handle->handle);
|
||||
struct os_fifo_q_handle *fifo = fifo_handle->handle;
|
||||
void *ret = k_fifo_peek_head(&fifo->handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *os_fifo_peek_tail(os_fifo_t *fifo_handle)
|
||||
{
|
||||
OS_ASS_HDL(os_fifo_q_is_valid(fifo_handle), fifo_handle->handle);
|
||||
struct os_fifo_q_handle *fifo = fifo_handle->handle;
|
||||
void *ret = k_fifo_peek_tail(&fifo->handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool os_fifo_q_is_valid(os_fifo_t *fifo_handle)
|
||||
{
|
||||
if (fifo_handle && fifo_handle->handle)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
struct os_queue_handle
|
||||
{
|
||||
k_queue_t handle;
|
||||
os_sem_t sem_send;
|
||||
os_sem_t sem_recv;
|
||||
};
|
||||
|
||||
os_state os_queue_create(os_queue_t *queue_handle, size_t queue_length, size_t item_size)
|
||||
{
|
||||
os_state ret;
|
||||
|
||||
do
|
||||
{
|
||||
struct os_queue_handle *queue = os_malloc(sizeof(*queue));
|
||||
if (queue == NULL)
|
||||
{
|
||||
queue_handle->handle = NULL;
|
||||
ret = OS_E_NOMEM;
|
||||
break;
|
||||
}
|
||||
|
||||
memset(queue, 0, sizeof(*queue));
|
||||
|
||||
if (k_queue_create(&queue->handle, queue_length, item_size) != 0)
|
||||
{
|
||||
os_free(queue);
|
||||
ret = OS_E_NOMEM;
|
||||
break;
|
||||
}
|
||||
|
||||
os_sem_create(&queue->sem_recv, 0, 1);
|
||||
os_sem_create(&queue->sem_send, 0, 1);
|
||||
queue_handle->handle = queue;
|
||||
|
||||
ret = OS_OK;
|
||||
|
||||
} while (0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
os_state os_queue_delete(os_queue_t *queue_handle)
|
||||
{
|
||||
OS_ASS_HDL(os_queue_is_valid(queue_handle), queue_handle->handle);
|
||||
|
||||
struct os_queue_handle *queue = queue_handle->handle;
|
||||
|
||||
os_scheduler_suspend();
|
||||
os_sem_delete(&queue->sem_recv);
|
||||
os_sem_delete(&queue->sem_send);
|
||||
k_queue_delete(&queue->handle);
|
||||
os_free(queue);
|
||||
queue_handle->handle = NULL;
|
||||
os_scheduler_resume();
|
||||
|
||||
return OS_OK;
|
||||
}
|
||||
|
||||
os_state os_queue_clr(os_queue_t *queue_handle)
|
||||
{
|
||||
OS_ASS_HDL(os_queue_is_valid(queue_handle), queue_handle->handle);
|
||||
|
||||
struct os_queue_handle *queue = queue_handle->handle;
|
||||
k_queue_clr(&queue->handle);
|
||||
|
||||
return OS_OK;
|
||||
}
|
||||
|
||||
void os_queue_regist(os_queue_t *queue_handle, os_work_t *work_handle, int delay_ticks)
|
||||
{
|
||||
struct os_queue_handle *queue = queue_handle->handle;
|
||||
k_queue_regist(&queue->handle, (k_work_t *)work_handle, delay_ticks);
|
||||
}
|
||||
|
||||
void os_queue_unregist(os_queue_t *queue_handle)
|
||||
{
|
||||
struct os_queue_handle *queue = queue_handle->handle;
|
||||
k_queue_unregist(&queue->handle);
|
||||
}
|
||||
|
||||
static void *_os_ipc_queue_recv(void *queue_handle, va_list arp)
|
||||
{
|
||||
void *dst = va_arg(arp, void *);
|
||||
if (k_queue_recv(queue_handle, dst) == 0)
|
||||
{
|
||||
return (void *)!NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
os_state os_queue_recv(os_queue_t *queue_handle, void *dst, os_time_t wait_ms)
|
||||
{
|
||||
OS_ASS_HDL(os_queue_is_valid(queue_handle), queue_handle->handle);
|
||||
|
||||
struct os_queue_handle *queue = queue_handle->handle;
|
||||
os_state ret;
|
||||
if (_os_wait_memory(_os_ipc_queue_recv, &queue->handle, &queue->sem_recv, wait_ms, dst) == NULL)
|
||||
{
|
||||
ret = OS_E_TIMEOUT;
|
||||
}
|
||||
else
|
||||
{
|
||||
os_sem_release(&queue->sem_send);
|
||||
ret = OS_OK;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void *_os_ipc_queue_send(void *queue_handle, va_list arp)
|
||||
{
|
||||
const void *src = va_arg(arp, void *);
|
||||
if (k_queue_send(queue_handle, src) == 0)
|
||||
{
|
||||
return (void *)!NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
os_state os_queue_send(os_queue_t *queue_handle, const void *src, os_time_t wait_ms)
|
||||
{
|
||||
OS_ASS_HDL(os_queue_is_valid(queue_handle), queue_handle->handle);
|
||||
|
||||
struct os_queue_handle *queue = queue_handle->handle;
|
||||
os_state ret;
|
||||
|
||||
if (_os_wait_memory(_os_ipc_queue_send, &queue->handle, &queue->sem_send, wait_ms, src) == NULL)
|
||||
{
|
||||
ret = OS_E_TIMEOUT;
|
||||
}
|
||||
else
|
||||
{
|
||||
os_sem_release(&queue->sem_recv);
|
||||
ret = OS_OK;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void *_os_ipc_queue_alloc(void *queue_handle, va_list arp)
|
||||
{
|
||||
return k_queue_alloc(queue_handle);
|
||||
}
|
||||
|
||||
void *os_queue_alloc(os_queue_t *queue_handle, os_time_t wait_ms)
|
||||
{
|
||||
OS_ASS_HDL(os_queue_is_valid(queue_handle), queue_handle->handle);
|
||||
|
||||
struct os_queue_handle *queue = queue_handle->handle;
|
||||
void *ret = _os_wait_memory(_os_ipc_queue_alloc, &queue->handle, &queue->sem_send, wait_ms);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
os_state os_queue_free(void *queue_data)
|
||||
{
|
||||
os_state ret;
|
||||
|
||||
if (k_queue_free(queue_data) == 0)
|
||||
{
|
||||
k_queue_t *handle = k_queue_read_handle(queue_data);
|
||||
struct os_queue_handle *queue = OS_CONTAINER_OF(handle, struct os_queue_handle, handle);
|
||||
os_sem_release(&queue->sem_send);
|
||||
ret = OS_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = OS_E_PARAM;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
os_state os_queue_put(void *queue_data)
|
||||
{
|
||||
os_state ret;
|
||||
|
||||
if (k_queue_put(queue_data) == 0)
|
||||
{
|
||||
k_queue_t *handle = k_queue_read_handle(queue_data);
|
||||
struct os_queue_handle *queue = OS_CONTAINER_OF(handle, struct os_queue_handle, handle);
|
||||
os_sem_release(&queue->sem_recv);
|
||||
ret = OS_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = OS_E_PARAM;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void *_os_ipc_queue_take(void *queue_handle, va_list arp)
|
||||
{
|
||||
return k_queue_take(queue_handle);
|
||||
}
|
||||
|
||||
void *os_queue_take(os_queue_t *queue_handle, os_time_t wait_ms)
|
||||
{
|
||||
OS_ASS_HDL(os_queue_is_valid(queue_handle), queue_handle->handle);
|
||||
|
||||
struct os_queue_handle *queue = queue_handle->handle;
|
||||
void *ret = _os_wait_memory(_os_ipc_queue_take, &queue->handle, &queue->sem_recv, wait_ms);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *os_queue_peek_head(os_queue_t *queue_handle)
|
||||
{
|
||||
OS_ASS_HDL(os_queue_is_valid(queue_handle), queue_handle->handle);
|
||||
struct os_queue_handle *queue = queue_handle->handle;
|
||||
void *ret = k_queue_peek_head(&queue->handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *os_queue_peek_tail(os_queue_t *queue_handle)
|
||||
{
|
||||
OS_ASS_HDL(os_queue_is_valid(queue_handle), queue_handle->handle);
|
||||
struct os_queue_handle *queue = queue_handle->handle;
|
||||
void *ret = k_queue_peek_tail(&queue->handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t os_queue_get_item_size(os_queue_t *queue_handle)
|
||||
{
|
||||
struct os_queue_handle *queue = queue_handle->handle;
|
||||
size_t ret = k_queue_get_item_size(&queue->handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool os_queue_is_valid(os_queue_t *queue_handle)
|
||||
{
|
||||
if (queue_handle && queue_handle->handle)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
struct os_pipe_handle
|
||||
{
|
||||
k_pipe_t handle;
|
||||
};
|
||||
|
||||
os_state os_pipe_create(os_pipe_t *pipe_handle, size_t pipe_size)
|
||||
{
|
||||
os_state ret;
|
||||
|
||||
do
|
||||
{
|
||||
struct os_pipe_handle *pipe = os_malloc(sizeof(*pipe));
|
||||
if (pipe == NULL)
|
||||
{
|
||||
pipe_handle->handle = NULL;
|
||||
ret = OS_E_NOMEM;
|
||||
}
|
||||
|
||||
memset(pipe, 0, sizeof(*pipe));
|
||||
|
||||
if (k_pipe_create(&pipe->handle, pipe_size) != 0)
|
||||
{
|
||||
os_free(pipe);
|
||||
ret = OS_E_NOMEM;
|
||||
}
|
||||
|
||||
pipe_handle->handle = pipe;
|
||||
|
||||
ret = OS_OK;
|
||||
|
||||
} while (0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
os_state os_pipe_delete(os_pipe_t *pipe_handle)
|
||||
{
|
||||
OS_ASS_HDL(os_pipe_is_valid(pipe_handle), pipe_handle->handle);
|
||||
|
||||
struct os_pipe_handle *pipe = pipe_handle->handle;
|
||||
|
||||
k_pipe_delete(&pipe->handle);
|
||||
os_free(pipe);
|
||||
pipe_handle->handle = NULL;
|
||||
|
||||
return OS_OK;
|
||||
}
|
||||
|
||||
os_state os_pipe_clr(os_pipe_t *pipe_handle)
|
||||
{
|
||||
OS_ASS_HDL(os_pipe_is_valid(pipe_handle), pipe_handle->handle);
|
||||
|
||||
struct os_pipe_handle *pipe = pipe_handle->handle;
|
||||
k_pipe_clr(&pipe->handle);
|
||||
|
||||
return OS_OK;
|
||||
}
|
||||
|
||||
void os_pipe_regist(os_pipe_t *pipe_handle, os_work_t *work_handle, int delay_ticks)
|
||||
{
|
||||
struct os_pipe_handle *pipe = pipe_handle->handle;
|
||||
k_pipe_regist(&pipe->handle, (k_work_t *)work_handle, delay_ticks);
|
||||
}
|
||||
|
||||
void os_pipe_unregist(os_pipe_t *pipe_handle)
|
||||
{
|
||||
struct os_pipe_handle *pipe = pipe_handle->handle;
|
||||
k_pipe_unregist(&pipe->handle);
|
||||
}
|
||||
|
||||
size_t os_pipe_poll_write(os_pipe_t *pipe_handle, uint8_t data)
|
||||
{
|
||||
struct os_pipe_handle *pipe = pipe_handle->handle;
|
||||
size_t ret = k_pipe_poll_write(&pipe->handle, data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t os_pipe_fifo_fill(os_pipe_t *pipe_handle, const void *data, size_t size)
|
||||
{
|
||||
struct os_pipe_handle *pipe = pipe_handle->handle;
|
||||
size_t ret = k_pipe_fifo_fill(&pipe->handle, data, size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t os_pipe_poll_read(os_pipe_t *pipe_handle, uint8_t *data)
|
||||
{
|
||||
struct os_pipe_handle *pipe = pipe_handle->handle;
|
||||
size_t ret = k_pipe_poll_read(&pipe->handle, data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t os_pipe_fifo_read(os_pipe_t *pipe_handle, void *data, size_t size)
|
||||
{
|
||||
struct os_pipe_handle *pipe = pipe_handle->handle;
|
||||
size_t ret = k_pipe_fifo_read(&pipe->handle, data, size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool os_pipe_is_ne(os_pipe_t *pipe_handle)
|
||||
{
|
||||
struct os_pipe_handle *pipe = pipe_handle->handle;
|
||||
bool ret = k_pipe_is_ne(&pipe->handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t os_pipe_get_valid_size(os_pipe_t *pipe_handle)
|
||||
{
|
||||
struct os_pipe_handle *pipe = pipe_handle->handle;
|
||||
size_t ret = k_pipe_get_valid_size(&pipe->handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t os_pipe_get_empty_size(os_pipe_t *pipe_handle)
|
||||
{
|
||||
struct os_pipe_handle *pipe = pipe_handle->handle;
|
||||
size_t ret = k_pipe_get_empty_size(&pipe->handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void os_pipe_peek_valid(os_pipe_t *pipe_handle, void **dst_base, size_t *dst_size)
|
||||
{
|
||||
struct os_pipe_handle *pipe = pipe_handle->handle;
|
||||
k_pipe_peek_valid(&pipe->handle, dst_base, dst_size);
|
||||
}
|
||||
|
||||
void os_pipe_peek_empty(os_pipe_t *pipe_handle, void **dst_base, size_t *dst_size)
|
||||
{
|
||||
struct os_pipe_handle *pipe = pipe_handle->handle;
|
||||
k_pipe_peek_empty(&pipe->handle, dst_base, dst_size);
|
||||
}
|
||||
|
||||
bool os_pipe_is_valid(os_pipe_t *pipe_handle)
|
||||
{
|
||||
if (pipe_handle && pipe_handle->handle)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
80
sal/esp32s3/kernel/os_mutex.c
Executable file
80
sal/esp32s3/kernel/os_mutex.c
Executable file
@@ -0,0 +1,80 @@
|
||||
#include "os/os.h"
|
||||
#include "os_util.h"
|
||||
#include "semphr.h"
|
||||
|
||||
os_state os_mutex_create(os_mutex_t *mutex)
|
||||
{
|
||||
OS_ASS_HDL(!os_mutex_is_valid(mutex), mutex->handle);
|
||||
|
||||
mutex->handle = xSemaphoreCreateMutex();
|
||||
if (mutex->handle == NULL)
|
||||
{
|
||||
OS_ERR("err %p\r\n", mutex->handle);
|
||||
return OS_FAIL;
|
||||
}
|
||||
|
||||
return OS_OK;
|
||||
}
|
||||
|
||||
os_state os_mutex_delete(os_mutex_t *mutex)
|
||||
{
|
||||
OS_ASS_HDL(os_mutex_is_valid(mutex), mutex->handle);
|
||||
|
||||
vSemaphoreDelete(mutex->handle);
|
||||
mutex->handle = NULL;
|
||||
return OS_OK;
|
||||
}
|
||||
|
||||
os_state os_mutex_lock(os_mutex_t *mutex, os_time_t wait_ms)
|
||||
{
|
||||
BaseType_t ret;
|
||||
|
||||
OS_ASS_HDL(os_mutex_is_valid(mutex), mutex->handle);
|
||||
|
||||
ret = xSemaphoreTake(mutex->handle, os_calc_msec_to_ticks(wait_ms));
|
||||
if (ret != pdPASS)
|
||||
{
|
||||
OS_DBG("%s() fail @ %d, %u ms\n", __func__, __LINE__, wait_ms);
|
||||
return OS_FAIL;
|
||||
}
|
||||
|
||||
return OS_OK;
|
||||
}
|
||||
|
||||
os_state os_mutex_unlock(os_mutex_t *mutex)
|
||||
{
|
||||
BaseType_t ret;
|
||||
|
||||
OS_ASS_HDL(os_mutex_is_valid(mutex), mutex->handle);
|
||||
|
||||
ret = xSemaphoreGive(mutex->handle);
|
||||
if (ret != pdPASS)
|
||||
{
|
||||
OS_DBG("%s() fail @ %d\n", __func__, __LINE__);
|
||||
return OS_FAIL;
|
||||
}
|
||||
|
||||
return OS_OK;
|
||||
}
|
||||
|
||||
os_thread_handle_t os_mutex_get_holder(os_mutex_t *mutex)
|
||||
{
|
||||
if (!os_mutex_is_valid(mutex))
|
||||
{
|
||||
return OS_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
return (os_thread_handle_t)xSemaphoreGetMutexHolder(mutex->handle);
|
||||
}
|
||||
|
||||
bool os_mutex_is_valid(os_mutex_t *mutex)
|
||||
{
|
||||
if (mutex && mutex->handle)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
105
sal/esp32s3/kernel/os_semaphore.c
Executable file
105
sal/esp32s3/kernel/os_semaphore.c
Executable file
@@ -0,0 +1,105 @@
|
||||
#include "os/os.h"
|
||||
#include "os_util.h"
|
||||
#include "semphr.h"
|
||||
|
||||
os_state os_sem_create(os_sem_t *sem, size_t init_value, size_t max_value)
|
||||
{
|
||||
OS_ASS_HDL(!os_sem_is_valid(sem), sem->handle);
|
||||
|
||||
sem->handle = xSemaphoreCreateCounting(max_value, init_value);
|
||||
if (sem->handle == NULL)
|
||||
{
|
||||
OS_ERR("err %p\r\n", sem->handle);
|
||||
return OS_FAIL;
|
||||
}
|
||||
|
||||
return OS_OK;
|
||||
}
|
||||
|
||||
os_state os_sem_delete(os_sem_t *sem)
|
||||
{
|
||||
OS_ASS_HDL(os_sem_is_valid(sem), sem->handle);
|
||||
|
||||
vSemaphoreDelete(sem->handle);
|
||||
sem->handle = NULL;
|
||||
return OS_OK;
|
||||
}
|
||||
|
||||
os_state os_sem_take(os_sem_t *sem, os_time_t wait_ms)
|
||||
{
|
||||
BaseType_t ret;
|
||||
BaseType_t taskWoken;
|
||||
|
||||
OS_ASS_HDL(os_sem_is_valid(sem), sem->handle);
|
||||
|
||||
if (os_is_isr_context())
|
||||
{
|
||||
if (wait_ms != 0)
|
||||
{
|
||||
OS_ERR("%s() in ISR, wait %u ms\n", __func__, wait_ms);
|
||||
return OS_E_ISR;
|
||||
}
|
||||
taskWoken = pdFALSE;
|
||||
ret = xSemaphoreTakeFromISR(sem->handle, &taskWoken);
|
||||
if (ret != pdPASS)
|
||||
{
|
||||
OS_DBG("%s() fail @ %d\n", __func__, __LINE__);
|
||||
return OS_E_TIMEOUT;
|
||||
}
|
||||
portYIELD_FROM_ISR(taskWoken);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = xSemaphoreTake(sem->handle, os_calc_msec_to_ticks(wait_ms));
|
||||
if (ret != pdPASS)
|
||||
{
|
||||
OS_DBG("%s() fail @ %d, %u ms\n", __func__, __LINE__, wait_ms);
|
||||
return OS_E_TIMEOUT;
|
||||
}
|
||||
}
|
||||
|
||||
return OS_OK;
|
||||
}
|
||||
|
||||
os_state os_sem_release(os_sem_t *sem)
|
||||
{
|
||||
BaseType_t ret;
|
||||
BaseType_t taskWoken;
|
||||
|
||||
OS_ASS_HDL(os_sem_is_valid(sem), sem->handle);
|
||||
|
||||
if (os_is_isr_context())
|
||||
{
|
||||
taskWoken = pdFALSE;
|
||||
ret = xSemaphoreGiveFromISR(sem->handle, &taskWoken);
|
||||
if (ret != pdPASS)
|
||||
{
|
||||
OS_DBG("%s() fail @ %d\n", __func__, __LINE__);
|
||||
return OS_FAIL;
|
||||
}
|
||||
portYIELD_FROM_ISR(taskWoken);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = xSemaphoreGive(sem->handle);
|
||||
if (ret != pdPASS)
|
||||
{
|
||||
OS_DBG("%s() fail @ %d\n", __func__, __LINE__);
|
||||
return OS_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
return OS_OK;
|
||||
}
|
||||
|
||||
bool os_sem_is_valid(os_sem_t *sem)
|
||||
{
|
||||
if (sem && sem->handle)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
184
sal/esp32s3/kernel/os_service.c
Executable file
184
sal/esp32s3/kernel/os_service.c
Executable file
@@ -0,0 +1,184 @@
|
||||
#include "os/os.h"
|
||||
#include "os_util.h"
|
||||
#include "task.h"
|
||||
|
||||
static size_t int_flag;
|
||||
static portMUX_TYPE s_os_service = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
int os_start(void *heap_mem, size_t heap_size)
|
||||
{
|
||||
extern int os_entry(void *heap, size_t size);
|
||||
return os_entry(heap_mem, heap_size);
|
||||
}
|
||||
|
||||
void os_int_entry(void)
|
||||
{
|
||||
os_interrupt_disable();
|
||||
++int_flag;
|
||||
os_interrupt_enable();
|
||||
}
|
||||
|
||||
void os_int_exit(void)
|
||||
{
|
||||
os_interrupt_disable();
|
||||
int_flag -= !!int_flag;
|
||||
os_interrupt_enable();
|
||||
}
|
||||
|
||||
bool os_is_isr_context(void)
|
||||
{
|
||||
if (int_flag)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void os_interrupt_disable(void)
|
||||
{
|
||||
portENTER_CRITICAL(&s_os_service);
|
||||
}
|
||||
|
||||
void os_interrupt_enable(void)
|
||||
{
|
||||
portEXIT_CRITICAL(&s_os_service);
|
||||
}
|
||||
|
||||
void os_scheduler_suspend(void)
|
||||
{
|
||||
vTaskSuspendAll();
|
||||
}
|
||||
|
||||
void os_scheduler_resume(void)
|
||||
{
|
||||
xTaskResumeAll();
|
||||
}
|
||||
|
||||
bool os_scheduler_is_running(void)
|
||||
{
|
||||
return (bool)(xTaskGetSchedulerState() == taskSCHEDULER_RUNNING);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS
|
||||
void os_sys_print_info(void)
|
||||
{
|
||||
const size_t bytes_per_task = 40; /* see vTaskList description */
|
||||
char *task_list_buffer = malloc(uxTaskGetNumberOfTasks() * bytes_per_task);
|
||||
if (task_list_buffer == NULL)
|
||||
{
|
||||
OS_LOG(1, "failed to allocate buffer for vTaskList output\r\n");
|
||||
return;
|
||||
}
|
||||
fputs("Task Name\tStatus\tPrio\tHWM\tTask#", stdout);
|
||||
#ifdef CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID
|
||||
fputs("\tAffinity", stdout);
|
||||
#endif
|
||||
fputs("\n", stdout);
|
||||
vTaskList(task_list_buffer);
|
||||
fputs(task_list_buffer, stdout);
|
||||
free(task_list_buffer);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void os_sys_print_info(void)
|
||||
{
|
||||
OS_LOG(1, "os_sys_print_info() not supported, please set configUSE_TRACE_FACILITY to 1\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
os_time_t os_get_sys_time(void)
|
||||
{
|
||||
os_time_t ticks_count = xTaskGetTickCount();
|
||||
return OS_TicksToMSecs(ticks_count);
|
||||
}
|
||||
|
||||
size_t os_get_sys_ticks(void)
|
||||
{
|
||||
return (size_t)xTaskGetTickCount();
|
||||
}
|
||||
|
||||
os_time_t os_calc_ticks_to_msec(size_t ticks)
|
||||
{
|
||||
os_time_t msec;
|
||||
|
||||
if (ticks == OS_WAIT_FOREVER)
|
||||
{
|
||||
msec = portMAX_DELAY;
|
||||
}
|
||||
else if (ticks == 0)
|
||||
{
|
||||
msec = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
msec = OS_TicksToMSecs(ticks);
|
||||
if (msec == 0)
|
||||
{
|
||||
msec = 1;
|
||||
}
|
||||
}
|
||||
return msec;
|
||||
}
|
||||
|
||||
size_t os_calc_msec_to_ticks(os_time_t msec)
|
||||
{
|
||||
size_t tick;
|
||||
|
||||
if (msec == OS_WAIT_FOREVER)
|
||||
{
|
||||
tick = portMAX_DELAY;
|
||||
}
|
||||
else if (msec == 0)
|
||||
{
|
||||
tick = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
tick = OS_MSecsToTicks(msec);
|
||||
if (tick == 0)
|
||||
{
|
||||
tick = 1;
|
||||
}
|
||||
}
|
||||
return tick;
|
||||
}
|
||||
|
||||
size_t os_cpu_usage(void)
|
||||
{
|
||||
return 100;
|
||||
}
|
||||
|
||||
#if (configUSE_POSIX_ERRNO == 1)
|
||||
|
||||
extern int FreeRTOS_errno;
|
||||
|
||||
int os_get_err(void)
|
||||
{
|
||||
return FreeRTOS_errno;
|
||||
}
|
||||
|
||||
void os_set_err(int err)
|
||||
{
|
||||
FreeRTOS_errno = err;
|
||||
}
|
||||
|
||||
#elif (configNUM_THREAD_LOCAL_STORAGE_POINTERS != 0)
|
||||
|
||||
#define OS_ERRNO_LOCATION_IDX 0
|
||||
|
||||
int os_get_err(void)
|
||||
{
|
||||
return (int)pvTaskGetThreadLocalStoragePointer(NULL, OS_ERRNO_LOCATION_IDX);
|
||||
}
|
||||
|
||||
void os_set_err(int err)
|
||||
{
|
||||
vTaskSetThreadLocalStoragePointer(NULL, OS_ERRNO_LOCATION_IDX, (void *)err);
|
||||
}
|
||||
|
||||
#endif
|
||||
277
sal/esp32s3/kernel/os_thread.c
Executable file
277
sal/esp32s3/kernel/os_thread.c
Executable file
@@ -0,0 +1,277 @@
|
||||
#include "os/os.h"
|
||||
#include "os_util.h"
|
||||
#include "task.h"
|
||||
#include "list/slist.h"
|
||||
|
||||
/* Macro used to convert os_priority to the kernel's real priority */
|
||||
#define OS_KERNEL_PRIO(prio) (prio)
|
||||
|
||||
static slist_t s_thread_list;
|
||||
|
||||
static void _os_delete(struct os_thread_handle *thread_handle)
|
||||
{
|
||||
os_scheduler_suspend();
|
||||
|
||||
slist_remove(&s_thread_list, &thread_handle->node);
|
||||
thread_handle->thread->handle = NULL;
|
||||
if (thread_handle->flag_free)
|
||||
{
|
||||
os_free(thread_handle->thread);
|
||||
}
|
||||
os_free(thread_handle);
|
||||
|
||||
os_scheduler_resume();
|
||||
}
|
||||
|
||||
static void _os_thread_start(void *arg)
|
||||
{
|
||||
struct os_thread_handle *thread_handle = arg;
|
||||
thread_handle->entry(thread_handle->arg);
|
||||
_os_delete(thread_handle);
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
os_state os_thread_init(os_thread_t *thread,
|
||||
const char *name,
|
||||
os_thread_entry_t entry,
|
||||
void *arg,
|
||||
void *stack_base,
|
||||
size_t stack_size,
|
||||
os_priority priority)
|
||||
{
|
||||
#if (configSUPPORT_STATIC_ALLOCATION == 1)
|
||||
|
||||
OS_ASS_HDL(!os_thread_is_valid(thread), thread->handle);
|
||||
|
||||
if (stack_size <= sizeof(struct os_thread_handle) + sizeof(StaticTask_t))
|
||||
{
|
||||
OS_ERR("err size: %d <= %d\r\n", stack_size, sizeof(struct os_thread_handle) + sizeof(StaticTask_t));
|
||||
return OS_FAIL;
|
||||
}
|
||||
|
||||
struct os_thread_handle *thread_handle = stack_base;
|
||||
StaticTask_t *pxTaskBuffer = (StaticTask_t *)&thread_handle[1];
|
||||
StackType_t *puxStackBuffer = (StackType_t *)&pxTaskBuffer[1];
|
||||
|
||||
thread_handle->thread = thread;
|
||||
thread_handle->entry = entry;
|
||||
thread_handle->arg = arg;
|
||||
thread_handle->flag_free = 0;
|
||||
thread_handle->pxCreatedTask = xTaskCreateStatic(_os_thread_start,
|
||||
name,
|
||||
stack_size / sizeof(StackType_t),
|
||||
thread_handle,
|
||||
OS_KERNEL_PRIO(priority),
|
||||
puxStackBuffer,
|
||||
pxTaskBuffer);
|
||||
thread->handle = thread_handle;
|
||||
return OS_OK;
|
||||
|
||||
#else
|
||||
|
||||
OS_ERR("err configSUPPORT_STATIC_ALLOCATION != 1\r\n");
|
||||
return OS_FAIL;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
os_state os_thread_create(os_thread_t *thread,
|
||||
const char *name,
|
||||
os_thread_entry_t entry,
|
||||
void *arg,
|
||||
size_t stack_size,
|
||||
os_priority priority)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (thread)
|
||||
{
|
||||
OS_ASS_HDL(!os_thread_is_valid(thread), thread->handle);
|
||||
}
|
||||
|
||||
struct os_thread_handle *thread_handle = os_malloc(sizeof(struct os_thread_handle));
|
||||
if (thread_handle == NULL)
|
||||
{
|
||||
return OS_E_NOMEM;
|
||||
}
|
||||
|
||||
if (thread == NULL)
|
||||
{
|
||||
thread = os_malloc(sizeof(os_thread_t));
|
||||
if (thread == NULL)
|
||||
{
|
||||
os_free(thread_handle);
|
||||
return OS_E_NOMEM;
|
||||
}
|
||||
memset(thread, 0, sizeof(os_thread_t));
|
||||
thread_handle->flag_free = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
thread_handle->flag_free = 0;
|
||||
}
|
||||
thread->handle = thread_handle;
|
||||
thread_handle->work_q_list = NULL;
|
||||
thread_handle->thread = thread;
|
||||
thread_handle->entry = entry;
|
||||
thread_handle->arg = arg;
|
||||
slist_init_node(&thread_handle->node);
|
||||
|
||||
os_scheduler_suspend();
|
||||
slist_insert_tail(&s_thread_list, &thread_handle->node);
|
||||
os_scheduler_resume();
|
||||
|
||||
ret = xTaskCreatePinnedToCore(_os_thread_start,
|
||||
name,
|
||||
stack_size / sizeof(StackType_t),
|
||||
thread_handle,
|
||||
OS_KERNEL_PRIO(priority),
|
||||
&thread_handle->pxCreatedTask,
|
||||
1);
|
||||
if (ret != pdPASS)
|
||||
{
|
||||
OS_ERR("err %d\r\n", ret);
|
||||
|
||||
os_scheduler_suspend();
|
||||
slist_remove(&s_thread_list, &thread_handle->node);
|
||||
os_scheduler_resume();
|
||||
|
||||
if (thread_handle->flag_free == 0)
|
||||
{
|
||||
thread->handle = NULL;
|
||||
}
|
||||
if (thread_handle->thread)
|
||||
{
|
||||
os_free(thread_handle->thread);
|
||||
}
|
||||
os_free(thread_handle);
|
||||
return OS_FAIL;
|
||||
}
|
||||
return OS_OK;
|
||||
}
|
||||
|
||||
os_state os_thread_delete(os_thread_t *thread)
|
||||
{
|
||||
if (thread == NULL) /* delete self */
|
||||
{
|
||||
struct os_thread_handle *thread_handle = os_thread_get_self();
|
||||
_os_delete(thread_handle);
|
||||
vTaskDelete(NULL);
|
||||
return OS_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
OS_ASS_HDL(os_thread_is_valid(thread), thread->handle);
|
||||
struct os_thread_handle *thread_handle = thread->handle;
|
||||
vTaskDelete(thread_handle->pxCreatedTask);
|
||||
_os_delete(thread_handle);
|
||||
return OS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
void os_thread_sleep(os_time_t msec)
|
||||
{
|
||||
vTaskDelay((TickType_t)os_calc_msec_to_ticks(msec));
|
||||
}
|
||||
|
||||
void os_thread_yield(void)
|
||||
{
|
||||
taskYIELD();
|
||||
}
|
||||
|
||||
void os_thread_suspend(os_thread_t *thread)
|
||||
{
|
||||
if (thread)
|
||||
{
|
||||
OS_ASS_HDL(os_thread_is_valid(thread), thread->handle);
|
||||
struct os_thread_handle *thread_handle = thread->handle;
|
||||
vTaskSuspend(thread_handle->pxCreatedTask);
|
||||
}
|
||||
else
|
||||
{
|
||||
vTaskSuspend(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void os_thread_resume(os_thread_t *thread)
|
||||
{
|
||||
OS_ASS_HDL(os_thread_is_valid(thread), thread->handle);
|
||||
struct os_thread_handle *thread_handle = thread->handle;
|
||||
vTaskResume(thread_handle->pxCreatedTask);
|
||||
}
|
||||
|
||||
os_thread_handle_t os_thread_get_self(void)
|
||||
{
|
||||
os_thread_handle_t ret = NULL;
|
||||
|
||||
os_scheduler_suspend();
|
||||
TaskHandle_t xTask = xTaskGetCurrentTaskHandle();
|
||||
struct os_thread_handle *thread_handle;
|
||||
struct os_thread_handle *prev_handle = NULL;
|
||||
int cnt = 0;
|
||||
SLIST_FOR_EACH_CONTAINER(&s_thread_list, thread_handle, node)
|
||||
{
|
||||
if (thread_handle->pxCreatedTask == xTask)
|
||||
{
|
||||
ret = thread_handle->thread->handle;
|
||||
break;
|
||||
}
|
||||
prev_handle = thread_handle;
|
||||
cnt++;
|
||||
}
|
||||
if (cnt > 5)
|
||||
{
|
||||
slist_remove_next(&s_thread_list, &prev_handle->node, &thread_handle->node);
|
||||
slist_insert_font(&s_thread_list, &thread_handle->node);
|
||||
}
|
||||
os_scheduler_resume();
|
||||
SYS_ASSERT(ret, "xTask: %p", xTask);
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char *os_thread_get_name(os_thread_t *thread)
|
||||
{
|
||||
struct os_thread_handle *thread_handle = thread->handle;
|
||||
return pcTaskGetName(thread_handle->pxCreatedTask);
|
||||
}
|
||||
|
||||
size_t os_thread_stack_min(os_thread_t *thread)
|
||||
{
|
||||
#if INCLUDE_uxTaskGetStackHighWaterMark
|
||||
TaskHandle_t xTask;
|
||||
|
||||
if (thread != NULL)
|
||||
{
|
||||
if (os_thread_is_valid(thread))
|
||||
{
|
||||
struct os_thread_handle *thread_handle = thread->handle;
|
||||
xTask = thread_handle->pxCreatedTask;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
xTask = NULL;
|
||||
}
|
||||
|
||||
extern UBaseType_t uxTaskGetStackHighWaterMark(TaskHandle_t xTask);
|
||||
return (uxTaskGetStackHighWaterMark(xTask) * sizeof(StackType_t));
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool os_thread_is_valid(os_thread_t *thread)
|
||||
{
|
||||
if (thread && thread->handle)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
219
sal/esp32s3/kernel/os_timer.c
Executable file
219
sal/esp32s3/kernel/os_timer.c
Executable file
@@ -0,0 +1,219 @@
|
||||
#include "os/os.h"
|
||||
#include "os_util.h"
|
||||
#include "timers.h"
|
||||
|
||||
/* TODO: what block time should be used ? */
|
||||
#define OS_TIMER_WAIT_FOREVER portMAX_DELAY
|
||||
#define OS_TIMER_WAIT_NONE 0
|
||||
|
||||
/* Timer private data definition */
|
||||
typedef struct OS_TimerPriv
|
||||
{
|
||||
TimerHandle_t handle; /* Timer handle */
|
||||
os_timer_cb_fn callback; /* Timer expire callback function */
|
||||
void *argument; /* Argument of timer expire callback function */
|
||||
} OS_TimerPriv_t;
|
||||
|
||||
static void _os_timer_cb(TimerHandle_t xTimer)
|
||||
{
|
||||
OS_TimerPriv_t *priv;
|
||||
|
||||
priv = pvTimerGetTimerID(xTimer);
|
||||
if (priv && priv->callback)
|
||||
{
|
||||
priv->callback(priv->argument);
|
||||
}
|
||||
else
|
||||
{
|
||||
OS_WRN("Invalid timer callback\n");
|
||||
}
|
||||
}
|
||||
|
||||
os_state os_timer_create(os_timer_t *timer, os_timer_cb_fn cb, void *arg)
|
||||
{
|
||||
OS_TimerPriv_t *priv;
|
||||
|
||||
OS_ASS_HDL(!os_timer_is_valid(timer), timer->handle);
|
||||
|
||||
priv = os_malloc(sizeof(OS_TimerPriv_t));
|
||||
if (priv == NULL)
|
||||
{
|
||||
return OS_E_NOMEM;
|
||||
}
|
||||
|
||||
priv->callback = cb;
|
||||
priv->argument = arg;
|
||||
priv->handle = xTimerCreate("",
|
||||
os_calc_msec_to_ticks(OS_WAIT_FOREVER),
|
||||
pdFALSE,
|
||||
priv,
|
||||
_os_timer_cb);
|
||||
if (priv->handle == NULL)
|
||||
{
|
||||
OS_ERR("err %p\r\n", priv->handle);
|
||||
os_free(priv);
|
||||
return OS_FAIL;
|
||||
}
|
||||
timer->handle = priv;
|
||||
return OS_OK;
|
||||
}
|
||||
|
||||
static TimerHandle_t _os_timer_get_handle(os_timer_t *timer)
|
||||
{
|
||||
OS_TimerPriv_t *priv = timer->handle;
|
||||
return priv->handle;
|
||||
}
|
||||
|
||||
os_state os_timer_delete(os_timer_t *timer)
|
||||
{
|
||||
TimerHandle_t handle;
|
||||
int ret;
|
||||
|
||||
OS_ASS_HDL(os_timer_is_valid(timer), timer->handle);
|
||||
|
||||
handle = _os_timer_get_handle(timer);
|
||||
ret = xTimerDelete(handle, OS_TIMER_WAIT_FOREVER);
|
||||
if (ret != pdPASS)
|
||||
{
|
||||
OS_ERR("err %d\r\n", ret);
|
||||
return OS_FAIL;
|
||||
}
|
||||
|
||||
OS_TimerPriv_t *priv = timer->handle;
|
||||
timer->handle = NULL;
|
||||
|
||||
os_free(priv);
|
||||
|
||||
return OS_OK;
|
||||
}
|
||||
|
||||
os_state os_timer_start(os_timer_t *timer)
|
||||
{
|
||||
TimerHandle_t handle;
|
||||
int ret;
|
||||
BaseType_t taskWoken;
|
||||
|
||||
OS_ASS_HDL(os_timer_is_valid(timer), timer->handle);
|
||||
|
||||
handle = _os_timer_get_handle(timer);
|
||||
|
||||
if (os_is_isr_context())
|
||||
{
|
||||
taskWoken = pdFALSE;
|
||||
ret = xTimerStartFromISR(handle, &taskWoken);
|
||||
if (ret != pdPASS)
|
||||
{
|
||||
OS_ERR("err %d\r\n", ret);
|
||||
return OS_FAIL;
|
||||
}
|
||||
portYIELD_FROM_ISR(taskWoken);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = xTimerStart(handle, OS_TIMER_WAIT_NONE);
|
||||
if (ret != pdPASS)
|
||||
{
|
||||
OS_ERR("err %d\r\n", ret);
|
||||
return OS_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
return OS_OK;
|
||||
}
|
||||
|
||||
os_state os_timer_set_period(os_timer_t *timer, os_timer_type_t type, os_time_t period_ms)
|
||||
{
|
||||
TimerHandle_t handle;
|
||||
TickType_t ticks;
|
||||
int ret;
|
||||
|
||||
OS_ASS_HDL(os_timer_is_valid(timer), timer->handle);
|
||||
|
||||
handle = _os_timer_get_handle(timer);
|
||||
ticks = os_calc_msec_to_ticks(period_ms);
|
||||
|
||||
if (os_is_isr_context())
|
||||
{
|
||||
BaseType_t taskWoken = pdFALSE;
|
||||
ret = xTimerChangePeriodFromISR(handle, ticks, &taskWoken);
|
||||
if (ret != pdPASS)
|
||||
{
|
||||
OS_ERR("err %d\r\n", ret);
|
||||
return OS_FAIL;
|
||||
}
|
||||
portYIELD_FROM_ISR(taskWoken);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = xTimerChangePeriod(handle, ticks, OS_TIMER_WAIT_NONE);
|
||||
if (ret != pdPASS)
|
||||
{
|
||||
OS_ERR("err %d\r\n", ret);
|
||||
return OS_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
vTimerSetReloadMode(handle, type == OS_TIMER_PERIODIC ? pdTRUE : pdFALSE);
|
||||
|
||||
return OS_OK;
|
||||
}
|
||||
|
||||
os_state os_timer_stop(os_timer_t *timer)
|
||||
{
|
||||
TimerHandle_t handle;
|
||||
int ret;
|
||||
BaseType_t taskWoken;
|
||||
|
||||
OS_ASS_HDL(os_timer_is_valid(timer), timer->handle);
|
||||
|
||||
handle = _os_timer_get_handle(timer);
|
||||
|
||||
if (os_is_isr_context())
|
||||
{
|
||||
taskWoken = pdFALSE;
|
||||
ret = xTimerStopFromISR(handle, &taskWoken);
|
||||
if (ret != pdPASS)
|
||||
{
|
||||
OS_ERR("err %d\r\n", ret);
|
||||
return OS_FAIL;
|
||||
}
|
||||
portYIELD_FROM_ISR(taskWoken);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = xTimerStop(handle, OS_TIMER_WAIT_FOREVER);
|
||||
if (ret != pdPASS)
|
||||
{
|
||||
OS_ERR("err %d\r\n", ret);
|
||||
return OS_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
return OS_OK;
|
||||
}
|
||||
|
||||
bool os_timer_is_pending(os_timer_t *timer)
|
||||
{
|
||||
TimerHandle_t handle;
|
||||
|
||||
if (!os_timer_is_valid(timer))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
handle = _os_timer_get_handle(timer);
|
||||
|
||||
return (xTimerIsTimerActive(handle) != pdFALSE);
|
||||
}
|
||||
|
||||
bool os_timer_is_valid(os_timer_t *timer)
|
||||
{
|
||||
if (timer && timer->handle)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
33
sal/esp32s3/kernel/os_util.h
Executable file
33
sal/esp32s3/kernel/os_util.h
Executable file
@@ -0,0 +1,33 @@
|
||||
#ifndef __OS_UTIL_H__
|
||||
#define __OS_UTIL_H__
|
||||
|
||||
#include "list/slist.h"
|
||||
#include "os/os_common.h"
|
||||
#include "os_debug.h"
|
||||
|
||||
#include "k_kit.h"
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
#define OS_TICK_RATE configTICK_RATE_HZ
|
||||
|
||||
typedef struct os_work_q_list
|
||||
{
|
||||
k_work_q_t work_q_handle;
|
||||
os_sem_t sem_handle;
|
||||
os_thread_t thread;
|
||||
} os_work_q_list_t;
|
||||
|
||||
struct os_thread_handle
|
||||
{
|
||||
slist_node_t node;
|
||||
TaskHandle_t pxCreatedTask;
|
||||
os_thread_t *thread;
|
||||
os_work_q_list_t *work_q_list;
|
||||
os_thread_entry_t entry;
|
||||
void *arg;
|
||||
uint8_t flag_free;
|
||||
};
|
||||
|
||||
#endif /* __OS_UTIL_H__ */
|
||||
27
sal/esp32s3/soc_shell.c
Normal file
27
sal/esp32s3/soc_shell.c
Normal file
@@ -0,0 +1,27 @@
|
||||
#include "shell/sh.h"
|
||||
|
||||
#include "esp_system.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
|
||||
#define CONFIG_SYS_LOG_DUMP_ON 1
|
||||
#define CONFIG_SYS_LOG_LEVEL SYS_LOG_LEVEL_INF
|
||||
#define SYS_LOG_DOMAIN "SOC"
|
||||
#include "sys_log.h"
|
||||
|
||||
#include "soc_shell_base.c"
|
||||
#include "soc_shell_nvs.c"
|
||||
|
||||
SH_DEF_SUB_CMD(
|
||||
sub_soc,
|
||||
SH_SETUP_CMD("base", "Basic information of the system", NULL, sub_soc_base), //
|
||||
SH_SETUP_CMD("nvs", "Partition for operating nvs", NULL, sub_soc_nvs), //
|
||||
);
|
||||
|
||||
SH_DEF_CMD(
|
||||
_register_cmd_soc,
|
||||
SH_SETUP_CMD("soc", "System on chip", NULL, sub_soc), );
|
||||
|
||||
void soc_shell_register(void)
|
||||
{
|
||||
sh_register_cmd(&_register_cmd_soc);
|
||||
}
|
||||
141
sal/esp32s3/soc_shell_base.c
Normal file
141
sal/esp32s3/soc_shell_base.c
Normal file
@@ -0,0 +1,141 @@
|
||||
/**
|
||||
* @file soc_shell_base.c
|
||||
* @author LokLiang
|
||||
* @brief 仅被 soc_shell.c 所包含,完成子命令列表及功能
|
||||
* @version 0.1
|
||||
* @date 2023-09-15
|
||||
*
|
||||
* @copyright Copyright (c) 2023
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SOC_SHELL_BASE_C__
|
||||
#define __SOC_SHELL_BASE_C__
|
||||
|
||||
#include "shell/sh.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "spi_flash_mmap.h"
|
||||
#include "esp_flash.h"
|
||||
#include "esp_chip_info.h"
|
||||
#include "task.h"
|
||||
|
||||
/* Unsigned integers. */
|
||||
#define PRIu8 "u"
|
||||
#define PRIu16 "u"
|
||||
#define PRIu32 "u"
|
||||
#define PRIu64 __PRI64_PREFIX "u"
|
||||
|
||||
SH_CMD_FN(_base_free);
|
||||
SH_CMD_FN(_base_heap);
|
||||
SH_CMD_FN(_base_version);
|
||||
SH_CMD_FN(_base_tasks);
|
||||
SH_CMD_FN(_base_restart);
|
||||
|
||||
SH_DEF_SUB_CMD(
|
||||
sub_soc_base,
|
||||
#ifdef CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS
|
||||
SH_SETUP_CMD("tasks", "Get information about running tasks", _base_tasks, NULL), //
|
||||
#endif
|
||||
SH_SETUP_CMD("free", "Get the current size of free heap memory", _base_free, NULL), //
|
||||
SH_SETUP_CMD("heap", "Get minimum size of free heap memory that was available during program execution", _base_heap, NULL), //
|
||||
SH_SETUP_CMD("version", "Get version of chip and SDK", _base_version, NULL), //
|
||||
SH_SETUP_CMD("restart", "Software reset of the chip", _base_restart, NULL), //
|
||||
);
|
||||
|
||||
SH_CMD_FN(_base_free)
|
||||
{
|
||||
sh_echo(sh_hdl, "当前堆内存空闲大小: %d bytes\r\n", esp_get_free_heap_size());
|
||||
return 0;
|
||||
}
|
||||
|
||||
SH_CMD_FN(_base_heap)
|
||||
{
|
||||
sh_echo(sh_hdl, "当前堆内存最少剩余: %d bytes\r\n", heap_caps_get_minimum_free_size(MALLOC_CAP_DEFAULT));
|
||||
return 0;
|
||||
}
|
||||
|
||||
SH_CMD_FN(_base_version)
|
||||
{
|
||||
const char *model;
|
||||
esp_chip_info_t info;
|
||||
uint32_t flash_size;
|
||||
esp_chip_info(&info);
|
||||
|
||||
switch (info.model)
|
||||
{
|
||||
case CHIP_ESP32:
|
||||
model = "ESP32";
|
||||
break;
|
||||
case CHIP_ESP32S2:
|
||||
model = "ESP32-S2";
|
||||
break;
|
||||
case CHIP_ESP32S3:
|
||||
model = "ESP32-S3";
|
||||
break;
|
||||
case CHIP_ESP32C3:
|
||||
model = "ESP32-C3";
|
||||
break;
|
||||
case CHIP_ESP32H2:
|
||||
model = "ESP32-H2";
|
||||
break;
|
||||
case CHIP_ESP32C2:
|
||||
model = "ESP32-C2";
|
||||
break;
|
||||
default:
|
||||
model = "Unknown";
|
||||
break;
|
||||
}
|
||||
|
||||
if (esp_flash_get_size(NULL, &flash_size) != ESP_OK)
|
||||
{
|
||||
sh_echo(sh_hdl, "Get flash size failed");
|
||||
return 1;
|
||||
}
|
||||
sh_echo(sh_hdl, "IDF Version:%s\r\n", esp_get_idf_version());
|
||||
sh_echo(sh_hdl, "Chip info:\r\n");
|
||||
sh_echo(sh_hdl, "\tmodel:%s\r\n", model);
|
||||
sh_echo(sh_hdl, "\tcores:%d\r\n", info.cores);
|
||||
sh_echo(sh_hdl, "\tfeature:%s%s%s%s%" PRIu32 "%s\r\n",
|
||||
info.features & CHIP_FEATURE_WIFI_BGN ? "/802.11bgn" : "",
|
||||
info.features & CHIP_FEATURE_BLE ? "/BLE" : "",
|
||||
info.features & CHIP_FEATURE_BT ? "/BT" : "",
|
||||
info.features & CHIP_FEATURE_EMB_FLASH ? "/Embedded-Flash:" : "/External-Flash:",
|
||||
flash_size / (1024 * 1024), " MB");
|
||||
sh_echo(sh_hdl, "\trevision number:%d\r\n", info.revision);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SH_CMD_FN(_base_tasks)
|
||||
{
|
||||
#ifdef CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS
|
||||
const size_t bytes_per_task = 40; /* see vTaskList description */
|
||||
char *task_list_buffer = malloc(uxTaskGetNumberOfTasks() * bytes_per_task);
|
||||
if (task_list_buffer == NULL)
|
||||
{
|
||||
sh_echo(sh_hdl, "failed to allocate buffer for vTaskList output\r\n");
|
||||
return -1;
|
||||
}
|
||||
sh_echo(sh_hdl, "Task Name\tStatus\tPrio\tHWM\tTask#", stdout);
|
||||
#ifdef CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID
|
||||
sh_echo(sh_hdl, "\tAffinity", stdout);
|
||||
#endif
|
||||
sh_echo(sh_hdl, "\r\n", stdout);
|
||||
vTaskList(task_list_buffer);
|
||||
sh_echo(sh_hdl, task_list_buffer, stdout);
|
||||
|
||||
sh_echo(sh_hdl, "Task_Name\tRun_Cnt\t\tUsage_Rate\r\n", stdout);
|
||||
vTaskGetRunTimeStats(task_list_buffer);
|
||||
sh_echo(sh_hdl, task_list_buffer, stdout);
|
||||
|
||||
free(task_list_buffer);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
SH_CMD_FN(_base_restart)
|
||||
{
|
||||
esp_restart();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
117
sal/esp32s3/soc_shell_nvs.c
Normal file
117
sal/esp32s3/soc_shell_nvs.c
Normal file
@@ -0,0 +1,117 @@
|
||||
/**
|
||||
* @file soc_shell_nvs.c
|
||||
* @author LokLiang
|
||||
* @brief 仅被 soc_shell.c 所包含,完成子命令列表及功能
|
||||
* @version 0.1
|
||||
* @date 2023-09-15
|
||||
*
|
||||
* @copyright Copyright (c) 2023
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SOC_SHELL_NVS_C__
|
||||
#define __SOC_SHELL_NVS_C__
|
||||
|
||||
#include "shell/sh.h"
|
||||
#include "shell/sh_vset.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "os/os.h"
|
||||
|
||||
static char s_nvs_str_buf[0x40];
|
||||
|
||||
static int _value_set_str(const char *argv[]) { SET_VAR(&s_nvs_str_buf, 0, 0); }
|
||||
|
||||
SH_CMD_FN(_nvs_dump);
|
||||
SH_CMD_FN(_nvs_erase);
|
||||
|
||||
SH_DEF_SUB_CMD(
|
||||
sub_soc_nvs,
|
||||
SH_SETUP_CMD("dump", "Dump blob value for given key <namespace> <key>", _nvs_dump, NULL), //
|
||||
SH_SETUP_CMD("erase", "Erase the default NVS partition", _nvs_erase, NULL), //
|
||||
);
|
||||
|
||||
SH_CMD_FN(_nvs_dump)
|
||||
{
|
||||
const char *argv_r[2] = {"", ""};
|
||||
size_t required_size;
|
||||
char namespace_buf[sizeof(s_nvs_str_buf)];
|
||||
char key_buf[sizeof(s_nvs_str_buf)];
|
||||
int err = 0;
|
||||
|
||||
argv_r[0] = argv[0];
|
||||
err = err ? err : _value_set_str(argv_r);
|
||||
if (err == 0)
|
||||
strcpy(namespace_buf, s_nvs_str_buf);
|
||||
|
||||
argv_r[0] = argv[1];
|
||||
err = err ? err : _value_set_str(argv_r);
|
||||
if (err == 0)
|
||||
strcpy(key_buf, s_nvs_str_buf);
|
||||
|
||||
if (err == 0)
|
||||
{
|
||||
nvs_handle nvs_hdl;
|
||||
if (nvs_open(namespace_buf, NVS_READONLY, &nvs_hdl) == ESP_OK)
|
||||
{
|
||||
err = nvs_get_blob(nvs_hdl, key_buf, NULL, &required_size);
|
||||
if (err == 0)
|
||||
{
|
||||
if (required_size)
|
||||
{
|
||||
void *data = os_malloc(required_size);
|
||||
if (data)
|
||||
{
|
||||
err = nvs_get_blob(nvs_hdl, key_buf, data, &required_size);
|
||||
if (err == 0)
|
||||
{
|
||||
SYS_LOG_DUMP(data, required_size, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
sh_echo(sh_hdl, "Can not get blob key: '%s'\r\n", key_buf);
|
||||
}
|
||||
os_free(data);
|
||||
}
|
||||
else
|
||||
{
|
||||
sh_echo(sh_hdl, "os_malloc() fail\r\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sh_echo(sh_hdl, "Blob data empty\r\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sh_echo(sh_hdl, "Can not get blob key: '%s'\r\n", key_buf);
|
||||
}
|
||||
nvs_close(nvs_hdl);
|
||||
}
|
||||
else
|
||||
{
|
||||
sh_echo(sh_hdl, "Can not open name space: '%s'\r\n", namespace_buf);
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
SH_CMD_FN(_nvs_erase)
|
||||
{
|
||||
sh_echo(sh_hdl, "正在擦除 NVS 分区 ...\r\n");
|
||||
esp_err_t err = nvs_flash_erase();
|
||||
if (err == ESP_OK)
|
||||
{
|
||||
sh_echo(sh_hdl, "操作成功,重启系统 ...\r\n");
|
||||
esp_restart();
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
sh_echo(sh_hdl, "操作异常: err = %d\r\n", err);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
24
sdkconfig.defaults
Normal file
24
sdkconfig.defaults
Normal file
@@ -0,0 +1,24 @@
|
||||
# This file was generated using idf.py save-defconfig. It can be edited manually.
|
||||
# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
|
||||
#
|
||||
CONFIG_IDF_TARGET="esp32c3"
|
||||
CONFIG_BOOTLOADER_LOG_LEVEL_WARN=y
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PRODUCT_TYPE_LEDSTRIP=y
|
||||
CONFIG_CAP_LED_STRIP=y
|
||||
CONFIG_LED_STRIP_SKIP_PWRUP=y
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BT_BLE_42_FEATURES_SUPPORTED=y
|
||||
CONFIG_ESP_HTTP_CLIENT_ENABLE_DIGEST_AUTH=y
|
||||
CONFIG_ESP_SLEEP_POWER_DOWN_FLASH=y
|
||||
CONFIG_ESP_IPC_TASK_STACK_SIZE=1536
|
||||
CONFIG_ESP_TIMER_TASK_STACK_SIZE=2048
|
||||
CONFIG_FREERTOS_HZ=1000
|
||||
CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=768
|
||||
CONFIG_FREERTOS_ENABLE_BACKWARD_COMPATIBILITY=y
|
||||
CONFIG_FREERTOS_TIMER_TASK_PRIORITY=25
|
||||
CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=1536
|
||||
CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID=y
|
||||
CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=y
|
||||
CONFIG_LOG_DEFAULT_LEVEL_NONE=y
|
||||
Reference in New Issue
Block a user