Files
arcs/apps/arcs-mini/services/service_led.c
2026-08-13 16:50:52 +08:00

194 lines
4.6 KiB
C

#include "shell.h"
#include "stdint.h"
#include "stdbool.h"
#include "string.h"
#define TAG "led"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "lisa_log.h"
#include "lisa_gpio.h"
#include "lisa_thread.h"
#include "Driver_GPIO.h"
#include "IOMuxManager.h"
#include "board.h"
#define GPIO_DEVICE "gpiob"
typedef enum {
LED_CMD_ON = 0,
LED_CMD_OFF,
LED_CMD_BLINK,
LED_CMD_STOP,
} led_cmd_e;
typedef struct {
led_cmd_e cmd;
uint32_t on_ms;
uint32_t off_ms;
} led_msg_t;
static lisa_thread_t *s_led_task = NULL;
static QueueHandle_t s_led_queue = NULL;
static lisa_device_t *gpio_dev;
static int led_hw_init(void)
{
gpio_dev = lisa_device_get(GPIO_DEVICE);
if (!lisa_device_ready(gpio_dev)) {
LOGE("Error: %s device not ready", GPIO_DEVICE);
return -1;
}
int ret = lisa_gpio_configure(gpio_dev, LED_PIN, LISA_GPIO_OUTPUT | LISA_GPIO_OUTPUT_INIT_HIGH);
if (ret != 0) {
LOGE("Error: GPIO configuration failed (code: %d)", ret);
return -1;
}
return 0;
}
static void led_hw_on(void)
{
lisa_gpio_write_pin(gpio_dev, LED_PIN, LISA_GPIO_LOW);
}
static void led_hw_off(void)
{
lisa_gpio_write_pin(gpio_dev, LED_PIN, LISA_GPIO_HIGH);
}
static void led_task(void *param)
{
(void)param;
led_msg_t msg;
uint32_t on_ms = 0;
uint32_t off_ms = 0;
int blinking = 0;
int led_state = 0;
TickType_t last_wake_time = 0;
TickType_t next_toggle_time = 0;
led_hw_init();
last_wake_time = xTaskGetTickCount();
for (;;) {
TickType_t wait_time = portMAX_DELAY;
if (blinking) {
TickType_t current_time = xTaskGetTickCount();
if (current_time >= next_toggle_time) {
if (led_state) {
led_hw_off();
led_state = 0;
next_toggle_time = current_time + pdMS_TO_TICKS(off_ms);
} else {
led_hw_on();
led_state = 1;
next_toggle_time = current_time + pdMS_TO_TICKS(on_ms);
}
}
wait_time = next_toggle_time > current_time ? (next_toggle_time - current_time) : 0;
}
if (xQueueReceive(s_led_queue, &msg, wait_time) == pdPASS) {
switch (msg.cmd) {
case LED_CMD_ON:
blinking = 0;
led_state = 1;
led_hw_on();
break;
case LED_CMD_OFF:
blinking = 0;
led_state = 0;
led_hw_off();
break;
case LED_CMD_BLINK:
if (msg.on_ms == 0 && msg.off_ms == 0) {
blinking = 0;
led_state = 0;
led_hw_off();
} else {
on_ms = msg.on_ms ? msg.on_ms : 100;
off_ms = msg.off_ms ? msg.off_ms : 100;
blinking = 1;
led_state = 0;
next_toggle_time = xTaskGetTickCount();
}
break;
case LED_CMD_STOP:
default:
blinking = 0;
led_state = 0;
led_hw_off();
break;
}
}
}
}
void service_led_init(void)
{
if (s_led_queue != NULL) {
return;
}
s_led_queue = xQueueCreate(4, sizeof(led_msg_t));
if (s_led_queue == NULL) {
LISA_LOGE(TAG, "create queue failed");
return;
}
lisa_thread_attr_t attr = {
.name = (uint8_t *)"led_task",
.stack_size = 2048,
.priority = LISA_OS_PRIORITY_LOW,
};
s_led_task = lisa_thread_create(&attr, led_task, NULL);
if (s_led_task == NULL) {
LISA_LOGE(TAG, "create led task failed");
vQueueDelete(s_led_queue);
s_led_queue = NULL;
return;
}
LISA_LOGI(TAG, "LED service initialized");
}
static inline void led_send_cmd(led_cmd_e cmd, uint32_t on_ms, uint32_t off_ms)
{
if (!s_led_queue) {
LISA_LOGW(TAG, "LED queue not ready");
return;
}
led_msg_t msg = {.cmd = cmd, .on_ms = on_ms, .off_ms = off_ms};
BaseType_t ret = xQueueSend(s_led_queue, &msg, pdMS_TO_TICKS(100));
if (ret != pdPASS) {
LISA_LOGW(TAG, "LED queue send failed");
}
}
void service_led_on(void)
{
led_send_cmd(LED_CMD_ON, 0, 0);
}
void service_led_off(void)
{
led_send_cmd(LED_CMD_OFF, 0, 0);
}
void service_led_blink(uint32_t on_ms, uint32_t off_ms)
{
led_send_cmd(LED_CMD_BLINK, on_ms, off_ms);
}
void service_led_stop(void)
{
led_send_cmd(LED_CMD_STOP, 0, 0);
}