JT-DT-YD4N02B_4G_RTT_MRS/packages/agile_led-1.1.1/agile_led.c

630 lines
15 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* @Author : stark1898y 1658608470@qq.com
* @Date : 2024-07-04 16:13:57
* @LastEditors: mbw && 1600520629@qq.com
* @LastEditTime: 2025-02-20 17:17:23
* @FilePath: \JT-DT-YD4N02A_RTT_MRS-NT26K\packages\agile_led-1.1.1\agile_led.c
* @Description :
*
* Copyright (c) 2024 by yzy, All Rights Reserved.
*/
/**
* @file agile_led.c
* @brief Agile Led 软件包源文件
* @author 马龙伟 (2544047213@qq.com)
* @version 1.1.1
* @date 2021-12-28
*
@verbatim
使用:
如果未使能 PKG_AGILE_LED_USING_THREAD_AUTO_INIT:
1. agile_led_env_init 初始化环境
2. 创建一个线程,周期调用 agile_led_process建议周期时间不要太长
- agile_led_create / agile_led_init 创建 / 初始化对象
- agile_led_start 启动运行
- agile_led_dynamic_change_light_mode / agile_led_static_change_light_mode 更改模式
该操作也可在启动运行前执行
- 如果需要感知对象执行结束agile_led_set_compelete_callback 设置回调函数
- 过程中需要强制停止,使用 agile_led_stop
- agile_led_on / agile_led_off / agile_led_toggle 单独操作对象
@endverbatim
*
* @attention
*
* <h2><center>&copy; Copyright (c) 2021 Ma Longwei.
* All rights reserved.</center></h2>
*
*/
#include <agile_led.h>
#include <stdlib.h>
#include <string.h>
#define PKG_AGILE_LED_USING_THREAD_AUTO_INIT
/** @defgroup RT_Thread_DBG_Configuration RT-Thread DBG Configuration
* @{
*/
/** @name RT-Thread DBG 功能配置
* @{
*/
#define DBG_ENABLE
#define DBG_COLOR
#define DBG_SECTION_NAME "agile_led"
#ifdef PKG_AGILE_LED_DEBUG
#define DBG_LEVEL DBG_LOG
#else
#define DBG_LEVEL DBG_INFO
#endif
#include <rtdbg.h>
/**
* @}
*/
/**
* @}
*/
#ifdef PKG_AGILE_LED_USING_THREAD_AUTO_INIT
/** @defgroup AGILE_LED_Thread_Auto_Init Agile Led Thread Auto Init
* @{
*/
/** @defgroup AGILE_LED_Thread_Auto_Init_Configuration Agile Led Thread Auto Init Configuration
* @{
*/
/** @name Agile Led 自动初始化线程配置
* @{
*/
#ifndef PKG_AGILE_LED_THREAD_STACK_SIZE
#define PKG_AGILE_LED_THREAD_STACK_SIZE 512 /**< Agile Led 线程堆栈大小 */
#endif
#ifndef PKG_AGILE_LED_THREAD_PRIORITY
#define PKG_AGILE_LED_THREAD_PRIORITY 12 /**< Agile Led 线程优先级 */
#endif
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
#endif /* PKG_AGILE_LED_USING_THREAD_AUTO_INIT */
/** @defgroup AGILE_LED_Private_Variables Agile Led Private Variables
* @{
*/
ALIGN(RT_ALIGN_SIZE)
static rt_slist_t _slist_head = RT_SLIST_OBJECT_INIT(_slist_head); /**< Agile Led 链表头节点 */
static struct rt_mutex _mtx; /**< Agile Led 互斥锁 */
static uint8_t _is_init = 0; /**< Agile Led 初始化完成标志 */
#ifdef PKG_AGILE_LED_USING_THREAD_AUTO_INIT
static struct rt_thread _thread; /**< Agile Led 线程控制块 */
static uint8_t _thread_stack[PKG_AGILE_LED_THREAD_STACK_SIZE]; /**< Agile Led 线程堆栈 */
#endif
/**
* @}
*/
/** @defgroup AGILE_LED_Private_Functions Agile Led Private Functions
* @{
*/
/**
* @brief Agile Led 对象默认操作完成回调函数
* @param led Agile Led 对象指针
*/
static void agile_led_default_compelete_callback(agile_led_t *led)
{
RT_ASSERT(led);
LOG_D("led pin:%d compeleted.", led->pin);
}
#ifdef RT_USING_HEAP
/**
* @brief 解析字符串获取 Agile Led 对象 light_arr 和 arr_num
* @param led Agile Led 对象指针
* @param light_mode 闪烁模式字符串
@verbatim
例子:
"100,200,100,200"
只支持正整数,按照亮灭亮灭规律
@endverbatim
* @return RT_EOK:成功; !=RT_EOK:异常
*/
static int agile_led_get_light_arr(agile_led_t *led, const char *light_mode)
{
RT_ASSERT(led);
RT_ASSERT(led->type == AGILE_LED_TYPE_DYNAMIC);
RT_ASSERT(led->light_arr == RT_NULL);
RT_ASSERT(led->arr_num == 0);
const char *ptr = light_mode;
while (*ptr) {
if (*ptr == ',')
led->arr_num++;
ptr++;
}
if (*(ptr - 1) != ',')
led->arr_num++;
if (led->arr_num == 0)
return -RT_ERROR;
uint32_t *light_arr = rt_malloc(led->arr_num * sizeof(uint32_t));
if (light_arr == RT_NULL)
return -RT_ENOMEM;
rt_memset(light_arr, 0, led->arr_num * sizeof(uint32_t));
ptr = light_mode;
for (uint32_t i = 0; i < led->arr_num; i++) {
light_arr[i] = atoi(ptr);
ptr = strchr(ptr, ',');
if (ptr)
ptr++;
}
led->light_arr = light_arr;
return RT_EOK;
}
#endif /* RT_USING_HEAP */
/**
* @}
*/
/** @defgroup AGILE_LED_Exported_Functions Agile Led Exported Functions
* @{
*/
#ifdef RT_USING_HEAP
/**
* @brief 创建 Agile Led 对象
* @param pin 控制 led 的引脚
* @param active_logic led 有效电平 (PIN_HIGH/PIN_LOW)
* @param light_mode 闪烁模式字符串
@verbatim
例子:
"100,200,100,200"
只支持正整数,按照亮灭亮灭规律
@endverbatim
* @param loop_cnt 循环次数 (负数为永久循环)
* @return !=RT_NULL:Agile Led 对象指针; RT_NULL:异常
*/
agile_led_t *agile_led_create(uint32_t pin, uint32_t active_logic, const char *light_mode, int32_t loop_cnt)
{
if (!_is_init) {
LOG_E("Please call agile_led_env_init first.");
return RT_NULL;
}
agile_led_t *led = (agile_led_t *)rt_malloc(sizeof(agile_led_t));
if (led == RT_NULL)
return RT_NULL;
led->type = AGILE_LED_TYPE_DYNAMIC;
led->active = 0;
led->pin = pin;
led->active_logic = active_logic;
led->light_arr = RT_NULL;
led->arr_num = 0;
led->arr_index = 0;
if (light_mode) {
if (agile_led_get_light_arr(led, light_mode) != RT_EOK) {
rt_free(led);
return RT_NULL;
}
}
led->loop_init = loop_cnt;
led->loop_cnt = led->loop_init;
led->tick_timeout = rt_tick_get();
led->compelete = agile_led_default_compelete_callback;
rt_slist_init(&(led->slist));
rt_pin_mode(pin, PIN_MODE_OUTPUT);
rt_pin_write(pin, !active_logic);
return led;
}
/**
* @brief 删除 Agile Led 对象
* @param led Agile Led 对象指针
* @return RT_EOK:成功
*/
int agile_led_delete(agile_led_t *led)
{
RT_ASSERT(led);
RT_ASSERT(led->type == AGILE_LED_TYPE_DYNAMIC);
rt_mutex_take(&_mtx, RT_WAITING_FOREVER);
rt_slist_remove(&_slist_head, &(led->slist));
led->slist.next = RT_NULL;
rt_mutex_release(&_mtx);
if (led->light_arr) {
rt_free((uint32_t *)led->light_arr);
led->light_arr = RT_NULL;
}
rt_free(led);
return RT_EOK;
}
/**
* @brief 动态设置 Agile Led 对象的模式
* @note Agile Led 对象必须是使用 agile_led_create 创建的
* @param led Agile Led 对象指针
* @param light_mode 闪烁模式字符串
@verbatim
例子:
"100,200,100,200"
只支持正整数,按照亮灭亮灭规律
@endverbatim
* @param loop_cnt 循环次数 (负数为永久循环)
* @return RT_EOK:成功; !=RT_EOK:异常
*/
int agile_led_dynamic_change_light_mode(agile_led_t *led, const char *light_mode, int32_t loop_cnt)
{
RT_ASSERT(led);
RT_ASSERT(led->type == AGILE_LED_TYPE_DYNAMIC);
rt_mutex_take(&_mtx, RT_WAITING_FOREVER);
if (light_mode) {
if (led->light_arr) {
rt_free((uint32_t *)led->light_arr);
led->light_arr = RT_NULL;
}
led->arr_num = 0;
if (agile_led_get_light_arr(led, light_mode) != RT_EOK) {
agile_led_stop(led);
rt_mutex_release(&_mtx);
return -RT_ERROR;
}
}
led->loop_init = loop_cnt;
led->arr_index = 0;
led->loop_cnt = led->loop_init;
led->tick_timeout = rt_tick_get();
rt_mutex_release(&_mtx);
return RT_EOK;
}
/**
* @brief 动态设置 Agile Led 对象的模式
* @note 该 API 已被 agile_led_dynamic_change_light_mode 替代,目前版本仍兼容,但不保证后续版本不会抛弃
* @param led Agile Led 对象指针
* @param light_mode 闪烁模式字符串
@verbatim
例子:
"100,200,100,200"
只支持正整数,按照亮灭亮灭规律
@endverbatim
* @param loop_cnt 循环次数 (负数为永久循环)
* @return RT_EOK:成功; !=RT_EOK:异常
*/
int agile_led_set_light_mode(agile_led_t *led, const char *light_mode, int32_t loop_cnt)
{
return agile_led_dynamic_change_light_mode(led, light_mode, loop_cnt);
}
#endif /* RT_USING_HEAP */
/**
* @brief 初始化 Agile Led 对象
* @param led Agile Led 对象指针
* @param pin 控制 led 的引脚
* @param active_logic led 有效电平 (PIN_HIGH/PIN_LOW)
* @param light_array 闪烁数组
@verbatim
例子:
[100, 200, 100, 200]
只支持正整数,按照亮灭亮灭规律
@endverbatim
* @param array_size 闪烁数组数目
* @param loop_cnt 循环次数 (负数为永久循环)
* @return RT_EOK:成功; !=RT_EOK:异常
*/
int agile_led_init(agile_led_t *led, uint32_t pin, uint32_t active_logic, const uint32_t *light_array, int array_size, int32_t loop_cnt)
{
RT_ASSERT(led);
if (!_is_init) {
LOG_E("Please call agile_led_env_init first.");
return -RT_ERROR;
}
led->type = AGILE_LED_TYPE_STATIC;
led->active = 0;
led->pin = pin;
led->active_logic = active_logic;
led->light_arr = light_array;
led->arr_num = array_size;
led->arr_index = 0;
led->loop_init = loop_cnt;
led->loop_cnt = led->loop_init;
led->tick_timeout = rt_tick_get();
led->compelete = agile_led_default_compelete_callback;
rt_slist_init(&(led->slist));
rt_pin_mode(pin, PIN_MODE_OUTPUT);
rt_pin_write(pin, !active_logic);
return RT_EOK;
}
/**
* @brief 静态设置 Agile Led 对象的模式
* @note Agile Led 对象必须是静态的
* @param led Agile Led 对象指针
* @param light_array 闪烁数组
@verbatim
例子:
[100, 200, 100, 200]
只支持正整数,按照亮灭亮灭规律
@endverbatim
* @param array_size 闪烁数组数目
* @param loop_cnt 循环次数 (负数为永久循环)
* @return RT_EOK:成功
*/
int agile_led_static_change_light_mode(agile_led_t *led, const uint32_t *light_array, int array_size, int32_t loop_cnt)
{
RT_ASSERT(led);
RT_ASSERT(led->type == AGILE_LED_TYPE_STATIC);
rt_mutex_take(&_mtx, RT_WAITING_FOREVER);
led->light_arr = light_array;
led->arr_num = array_size;
led->arr_index = 0;
led->loop_init = loop_cnt;
led->loop_cnt = led->loop_init;
led->tick_timeout = rt_tick_get();
rt_mutex_release(&_mtx);
return RT_EOK;
}
/**
* @brief 启动 Agile Led 对象,根据设置的模式执行动作
* @param led Agile Led 对象指针
* @return RT_EOK:成功; !=RT_OK:异常
*/
int agile_led_start(agile_led_t *led)
{
RT_ASSERT(led);
rt_mutex_take(&_mtx, RT_WAITING_FOREVER);
if (led->active) {
rt_mutex_release(&_mtx);
return -RT_ERROR;
}
if ((led->light_arr == RT_NULL) || (led->arr_num == 0)) {
rt_mutex_release(&_mtx);
return -RT_ERROR;
}
led->arr_index = 0;
led->loop_cnt = led->loop_init;
led->tick_timeout = rt_tick_get();
rt_slist_append(&_slist_head, &(led->slist));
led->active = 1;
rt_mutex_release(&_mtx);
return RT_EOK;
}
/**
* @brief 停止 Agile Led 对象
* @param led Agile Led 对象指针
* @return RT_EOK:成功
*/
int agile_led_stop(agile_led_t *led)
{
RT_ASSERT(led);
rt_mutex_take(&_mtx, RT_WAITING_FOREVER);
if (!led->active) {
rt_mutex_release(&_mtx);
return RT_EOK;
}
rt_slist_remove(&_slist_head, &(led->slist));
led->slist.next = RT_NULL;
led->active = 0;
rt_mutex_release(&_mtx);
return RT_EOK;
}
/**
* @brief 设置 Agile Led 对象操作完成的回调函数
* @param led Agile Led 对象指针
* @param compelete 操作完成回调函数
* @return RT_EOK:成功
*/
int agile_led_set_compelete_callback(agile_led_t *led, void (*compelete)(agile_led_t *led))
{
RT_ASSERT(led);
rt_mutex_take(&_mtx, RT_WAITING_FOREVER);
led->compelete = compelete;
rt_mutex_release(&_mtx);
return RT_EOK;
}
/**
* @brief Agile Led 对象电平翻转
* @param led Agile Led 对象指针
*/
void agile_led_toggle(agile_led_t *led)
{
RT_ASSERT(led);
rt_pin_write(led->pin, !rt_pin_read(led->pin));
}
/**
* @brief Agile Led 对象亮
* @param led Agile Led 对象指针
*/
void agile_led_on(agile_led_t *led)
{
RT_ASSERT(led);
rt_pin_write(led->pin, led->active_logic);
}
/**
* @brief Agile Led 对象灭
* @param led Agile Led 对象指针
*/
void agile_led_off(agile_led_t *led)
{
RT_ASSERT(led);
rt_pin_write(led->pin, !led->active_logic);
}
/**
* @brief 处理所有 Agile Led 对象
* @note 如果使能 PKG_AGILE_LED_USING_THREAD_AUTO_INIT, 这个函数将被自动初始化线程 5ms 周期调用。
* 用户调用需要创建一个线程并将这个函数放入 while (1) {} 中。
*/
void agile_led_process(void)
{
rt_slist_t *node;
rt_mutex_take(&_mtx, RT_WAITING_FOREVER);
rt_slist_for_each(node, &_slist_head)
{
agile_led_t *led = rt_slist_entry(node, agile_led_t, slist);
if (led->loop_cnt == 0) {
agile_led_stop(led);
if (led->compelete) {
led->compelete(led);
}
node = &_slist_head;
continue;
}
__repeat:
if ((rt_tick_get() - led->tick_timeout) < (RT_TICK_MAX / 2)) {
if (led->arr_index < led->arr_num) {
if (led->light_arr[led->arr_index] == 0) {
led->arr_index++;
goto __repeat;
}
if (led->arr_index % 2) {
agile_led_off(led);
} else {
agile_led_on(led);
}
led->tick_timeout = rt_tick_get() + rt_tick_from_millisecond(led->light_arr[led->arr_index]);
led->arr_index++;
} else {
led->arr_index = 0;
if (led->loop_cnt > 0)
led->loop_cnt--;
}
}
}
rt_mutex_release(&_mtx);
}
/**
* @brief Agile Led 环境初始化
* @note 使用其他 API 之前该函数必须被调用。
* 如果使能 PKG_AGILE_LED_USING_THREAD_AUTO_INIT, 这个函数将被自动调用。
*/
void agile_led_env_init(void)
{
if (_is_init)
return;
rt_mutex_init(&_mtx, "led_mtx", RT_IPC_FLAG_FIFO);
_is_init = 1;
}
/**
* @}
*/
#ifdef PKG_AGILE_LED_USING_THREAD_AUTO_INIT
/** @addtogroup AGILE_LED_Thread_Auto_Init
* @{
*/
/** @defgroup AGILE_LED_Thread_Auto_Init_Functions Agile Led Thread Auto Init Functions
* @{
*/
/**
* @brief Agile Led 内部线程函数入口
* @param parameter 线程参数
*/
static void agile_led_auto_thread_entry(void *parameter)
{
while (1) {
agile_led_process();
rt_thread_mdelay(20);
}
}
/**
* @brief Agile Led 内部线程初始化
* @return RT_EOK:成功
*/
static int agile_led_auto_thread_init(void)
{
agile_led_env_init();
rt_thread_init(&_thread,
"agled",
agile_led_auto_thread_entry,
RT_NULL,
&_thread_stack[0],
sizeof(_thread_stack),
PKG_AGILE_LED_THREAD_PRIORITY,
10);
rt_thread_startup(&_thread);
return RT_EOK;
}
INIT_PREV_EXPORT(agile_led_auto_thread_init);
/**
* @}
*/
/**
* @}
*/
#endif /* PKG_AGILE_LED_USING_THREAD_AUTO_INIT */