/*
* @Author : stark1898y 1658608470@qq.com
* @Date : 2024-07-04 16:13:57
* @LastEditors: mbw && 1600520629@qq.com
* @LastEditTime: 2024-12-23 10:01:08
* @FilePath: \JT-DT-YD4N02A_RTT_MRS-4G\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
*
*
© Copyright (c) 2021 Ma Longwei.
* All rights reserved.
*
*/
#include
#include
#include
#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
/**
* @}
*/
/**
* @}
*/
#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 */