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

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