385 lines
12 KiB
C
385 lines
12 KiB
C
|
/****************************************************************************
|
||
|
|
||
|
Copyright(c) 2019 by Aerospace C.Power (Chongqing) Microelectronics. ALL RIGHTS RESERVED.
|
||
|
|
||
|
This Information is proprietary to Aerospace C.Power (Chongqing) Microelectronics and MAY NOT
|
||
|
be copied by any method or incorporated into another program without
|
||
|
the express written consent of Aerospace C.Power. This Information or any portion
|
||
|
thereof remains the property of Aerospace C.Power. The Information contained herein
|
||
|
is believed to be accurate and Aerospace C.Power assumes no responsibility or
|
||
|
liability for its use in any way and conveys no license or title under
|
||
|
any patent or copyright and makes no representation or warranty that this
|
||
|
Information is free from patent or copyright infringement.
|
||
|
|
||
|
****************************************************************************/
|
||
|
|
||
|
/* os_shim header files */
|
||
|
#include "os_types.h"
|
||
|
#include "os_task.h"
|
||
|
#include "os_event.h"
|
||
|
#include "os_timer.h"
|
||
|
|
||
|
/* iot common header files */
|
||
|
#include "iot_module.h"
|
||
|
#include "iot_errno.h"
|
||
|
#include "iot_queue.h"
|
||
|
#include "iot_mem_pool.h"
|
||
|
#include "iot_dbglog_parser.h"
|
||
|
#include "iot_dbglog_api.h"
|
||
|
#include "iot_task.h"
|
||
|
#include "iot_utils.h"
|
||
|
#include "iot_io.h"
|
||
|
|
||
|
/* task message queue */
|
||
|
typedef struct _iot_task_msg_queue {
|
||
|
/* queue to link the message */
|
||
|
iot_msg_queue_t q;
|
||
|
/* current quota of the queue */
|
||
|
uint8_t curr_quota;
|
||
|
/* assgined quota of the queue */
|
||
|
uint8_t quota;
|
||
|
/* flag to mark if quota feature enabled for this queue */
|
||
|
uint8_t quota_en;
|
||
|
/* reserved for future */
|
||
|
uint8_t reserved;
|
||
|
} iot_task_msg_queue_t;
|
||
|
|
||
|
|
||
|
typedef struct _iot_task {
|
||
|
/* task configuration */
|
||
|
iot_task_config_t cfg;
|
||
|
/* task handle */
|
||
|
os_task_h task_h;
|
||
|
/* pointer to task message queues */
|
||
|
iot_task_msg_queue_t msg_q[IOT_TASK_QUEUE_CNT_MAX];
|
||
|
/* task messages pool */
|
||
|
iot_mem_pool_t *msg_p;
|
||
|
} iot_task_t;
|
||
|
|
||
|
static void iot_task_func(void* arg)
|
||
|
{
|
||
|
uint8_t i;
|
||
|
uint32_t events;
|
||
|
iot_task_t *task = (iot_task_t *)arg;
|
||
|
iot_msg_entry_t *entry;
|
||
|
iot_task_msg_t *msg;
|
||
|
iot_task_msg_queue_t *pq;
|
||
|
uint8_t quota_disbled_q_cnt = 0;
|
||
|
uint8_t quota_enabled_q_cnt = 0;
|
||
|
uint8_t quota_exhausted_q_cnt = 0;
|
||
|
iot_task_msg_queue_t *quota_disbled_q[IOT_TASK_QUEUE_CNT_MAX];
|
||
|
iot_task_msg_queue_t *quota_enabled_q[IOT_TASK_QUEUE_CNT_MAX];
|
||
|
iot_task_msg_queue_t *quota_exhausted_q[IOT_TASK_QUEUE_CNT_MAX];
|
||
|
|
||
|
iot_printf("%s task %p, exe func %p\n", __FUNCTION__, task,
|
||
|
task->cfg.msg_exe_func);
|
||
|
iot_dbglog_input(IOT_TASK_MID, DBGLOG_INFO_LVL_2,
|
||
|
IOT_TASK_FUNC_ID, 2, task, task->cfg.msg_exe_func);
|
||
|
|
||
|
/* check if quota enabled and disabled queue exist */
|
||
|
for (i = 0; i < task->cfg.queue_cnt; i++) {
|
||
|
pq = &task->msg_q[i];
|
||
|
if (pq->quota_en) {
|
||
|
quota_enabled_q[quota_enabled_q_cnt] = pq;
|
||
|
quota_enabled_q_cnt++;
|
||
|
} else {
|
||
|
quota_disbled_q[quota_disbled_q_cnt] = pq;
|
||
|
quota_disbled_q_cnt++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for (;;) {
|
||
|
/* waiting for messages and task events.
|
||
|
* always handle taks event firstly.
|
||
|
*/
|
||
|
events = os_wait_task_event_with_v(MAX_TIME);
|
||
|
|
||
|
handle_event:
|
||
|
if (events && task->cfg.task_event_func)
|
||
|
task->cfg.task_event_func(task, events);
|
||
|
|
||
|
handle_msg:
|
||
|
/* check quota disabled queue */
|
||
|
if (quota_disbled_q_cnt) {
|
||
|
/* check message queues based on priority */
|
||
|
for (i = 0; i < quota_disbled_q_cnt; i++) {
|
||
|
pq = quota_disbled_q[i];
|
||
|
entry = iot_msg_queue_get(&pq->q);
|
||
|
if (entry) {
|
||
|
/* get message and handle it */
|
||
|
msg = container_of(entry, iot_task_msg_t, link);
|
||
|
task->cfg.msg_exe_func(task, msg);
|
||
|
/* check if any task event pending */
|
||
|
events = os_wait_task_event_with_v(0);
|
||
|
if (events)
|
||
|
goto handle_event;
|
||
|
/* always search from highest priority queue with quota
|
||
|
* disabled.
|
||
|
*/
|
||
|
goto handle_msg;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* check quota enabled queue */
|
||
|
if (quota_enabled_q_cnt) {
|
||
|
quota_exhausted_q_cnt = 0;
|
||
|
/* check message queues based on priority */
|
||
|
for (i = 0; i < quota_enabled_q_cnt; i++) {
|
||
|
pq = quota_enabled_q[i];
|
||
|
/* check if quota available for this queue */
|
||
|
if (pq->curr_quota == 0) {
|
||
|
quota_exhausted_q[quota_exhausted_q_cnt] = pq;
|
||
|
quota_exhausted_q_cnt++;
|
||
|
continue;
|
||
|
}
|
||
|
entry = iot_msg_queue_get(&pq->q);
|
||
|
if (entry) {
|
||
|
/* get message and handle it */
|
||
|
msg = container_of(entry, iot_task_msg_t, link);
|
||
|
task->cfg.msg_exe_func(task, msg);
|
||
|
pq->curr_quota--;
|
||
|
/* check if any task event pending */
|
||
|
events = os_wait_task_event_with_v(0);
|
||
|
if (events)
|
||
|
goto handle_event;
|
||
|
/* always search from highest priority queue with quota
|
||
|
* disabled.
|
||
|
*/
|
||
|
goto handle_msg;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (quota_exhausted_q_cnt == quota_enabled_q_cnt) {
|
||
|
/* no quota available queue exist, re-assign quota */
|
||
|
for (i = 0; i < quota_enabled_q_cnt; i++) {
|
||
|
pq = quota_enabled_q[i];
|
||
|
pq->curr_quota = pq->quota;
|
||
|
}
|
||
|
goto handle_msg;
|
||
|
} else {
|
||
|
/* check if any quota exhausted queue exist */
|
||
|
for (i = 0; i < quota_exhausted_q_cnt; i++) {
|
||
|
pq = quota_exhausted_q[i];
|
||
|
entry = iot_msg_queue_get(&pq->q);
|
||
|
if (entry) {
|
||
|
/* get message and handle it */
|
||
|
msg = container_of(entry, iot_task_msg_t, link);
|
||
|
task->cfg.msg_exe_func(task, msg);
|
||
|
/* check if any task event pending */
|
||
|
events = os_wait_task_event_with_v(0);
|
||
|
if (events)
|
||
|
goto handle_event;
|
||
|
/* always search from highest priority queue with quota
|
||
|
* disabled.
|
||
|
*/
|
||
|
goto handle_msg;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
iot_task_h iot_task_create_with_name(module_id_t module, iot_task_config_t *cfg,
|
||
|
const char *name)
|
||
|
{
|
||
|
uint8_t i;
|
||
|
uint32_t ret;
|
||
|
iot_task_t *task = NULL;
|
||
|
|
||
|
if (cfg->msg_exe_func == NULL || cfg->msg_cancel_func == NULL)
|
||
|
goto out;
|
||
|
|
||
|
if (cfg->msg_cnt == 0 || cfg->msg_size == 0)
|
||
|
goto out;
|
||
|
|
||
|
if (cfg->queue_cnt == 0 || cfg->queue_cnt > IOT_TASK_QUEUE_CNT_MAX)
|
||
|
goto out;
|
||
|
|
||
|
if (cfg->task_prio < OS_TASK_PRIO_LOWEST ||
|
||
|
cfg->task_prio > OS_TASK_PRIO_HIGHEST)
|
||
|
goto out;
|
||
|
|
||
|
task = os_mem_malloc(module, sizeof(*task));
|
||
|
if (task == NULL)
|
||
|
goto out;
|
||
|
|
||
|
task->cfg = *cfg;
|
||
|
|
||
|
/* allocate global messages pool */
|
||
|
ret = iot_mem_pool_new(module, cfg->msg_cnt,
|
||
|
cfg->msg_size, &task->msg_p, 1);
|
||
|
if (ret)
|
||
|
goto err_pool;
|
||
|
|
||
|
|
||
|
/* initialize message queues */
|
||
|
for (i = 0; i < cfg->queue_cnt; i++) {
|
||
|
ret = iot_msg_queue_init(&task->msg_q[i].q);
|
||
|
if (cfg->queue_cfg[i].quota) {
|
||
|
/* enable quota for this queue */
|
||
|
task->msg_q[i].quota_en = 1;
|
||
|
task->msg_q[i].quota = cfg->queue_cfg[i].quota;
|
||
|
task->msg_q[i].curr_quota = task->msg_q[i].quota;
|
||
|
} else {
|
||
|
/* disable quota for this queue */
|
||
|
task->msg_q[i].quota_en = 0;
|
||
|
task->msg_q[i].quota = 0;
|
||
|
task->msg_q[i].curr_quota = 0;
|
||
|
}
|
||
|
if (ret) {
|
||
|
for (; i > 0; i--) {
|
||
|
iot_msg_queue_deinit(&task->msg_q[i - 1].q);
|
||
|
}
|
||
|
goto err_queue;
|
||
|
}
|
||
|
}
|
||
|
/* start task */
|
||
|
task->task_h = os_create_task_smp_ext(iot_task_func, task,
|
||
|
cfg->task_prio, cfg->stack_size, name, cfg->core_id);
|
||
|
iot_printf("%s task %p, exe func %p\n", __FUNCTION__,
|
||
|
task, cfg->msg_exe_func);
|
||
|
iot_dbglog_input(IOT_TASK_MID, DBGLOG_INFO_LVL_2,
|
||
|
IOT_TASK_CREATE_ID, 2, (uint32_t)task, (uint32_t)cfg->msg_exe_func);
|
||
|
|
||
|
if (task->task_h == NULL)
|
||
|
goto err_task;
|
||
|
|
||
|
goto out;
|
||
|
|
||
|
err_task:
|
||
|
for (i = 0; i < cfg->queue_cnt; i++)
|
||
|
iot_msg_queue_deinit(&task->msg_q[i].q);
|
||
|
err_queue:
|
||
|
iot_mem_pool_destroy(task->msg_p);
|
||
|
err_pool:
|
||
|
os_mem_free(task);
|
||
|
task = NULL;
|
||
|
out:
|
||
|
return task;
|
||
|
}
|
||
|
|
||
|
void iot_task_delete(iot_task_h task_h)
|
||
|
{
|
||
|
uint8_t i;
|
||
|
iot_msg_queue_t *pq;
|
||
|
iot_msg_entry_t *entry;
|
||
|
iot_task_msg_t *msg;
|
||
|
iot_task_t *task = (iot_task_t *)task_h;
|
||
|
|
||
|
if (task->task_h) {
|
||
|
/* delete iot task */
|
||
|
os_delete_task(task->task_h);
|
||
|
task->task_h = NULL;
|
||
|
|
||
|
for (i = 0; i < task->cfg.queue_cnt; i++) {
|
||
|
pq = &task->msg_q[i].q;
|
||
|
entry = iot_msg_queue_get(pq);
|
||
|
while (entry) {
|
||
|
/* get messages */
|
||
|
msg = container_of(entry, iot_task_msg_t, link);
|
||
|
task->cfg.msg_cancel_func(task, msg);
|
||
|
entry = iot_msg_queue_get(pq);
|
||
|
}
|
||
|
|
||
|
/* deinit the sg message queue */
|
||
|
iot_msg_queue_deinit(pq);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
iot_printf("%s task %p, exe func %p\n", __FUNCTION__, task,
|
||
|
task->cfg.msg_exe_func);
|
||
|
iot_dbglog_input(IOT_TASK_MID, DBGLOG_INFO_LVL_2,
|
||
|
IOT_TASK_DELETE_ID, 2, task, task->cfg.msg_exe_func);
|
||
|
|
||
|
iot_mem_pool_destroy(task->msg_p);
|
||
|
|
||
|
os_mem_free(task);
|
||
|
}
|
||
|
|
||
|
iot_task_msg_t *iot_task_alloc_msg_with_reserved(iot_task_h task_h,
|
||
|
uint32_t reserved)
|
||
|
{
|
||
|
iot_task_t *task = (iot_task_t *)task_h;
|
||
|
iot_task_msg_t *msg;
|
||
|
|
||
|
msg = iot_mem_pool_alloc_with_reserve(task->msg_p, reserved);
|
||
|
if (msg)
|
||
|
iot_msg_entry_init(&msg->link);
|
||
|
|
||
|
return msg;
|
||
|
}
|
||
|
|
||
|
void iot_task_free_msg(iot_task_h task_h, iot_task_msg_t *msg)
|
||
|
{
|
||
|
iot_task_t *task = (iot_task_t *)task_h;
|
||
|
iot_mem_pool_free(task->msg_p, msg);
|
||
|
}
|
||
|
|
||
|
void iot_task_queue_msg(iot_task_h task_h, iot_task_msg_t *msg, uint8_t prio)
|
||
|
{
|
||
|
iot_task_t *task = (iot_task_t *)task_h;
|
||
|
|
||
|
IOT_ASSERT(prio < task->cfg.queue_cnt);
|
||
|
iot_msg_queue_put(&task->msg_q[prio].q, &msg->link);
|
||
|
os_set_task_event(task->task_h);
|
||
|
}
|
||
|
|
||
|
typedef struct iot_task_msg_check_param {
|
||
|
iot_msg_entry_t *head;
|
||
|
uint16_t type;
|
||
|
uint16_t id;
|
||
|
} iot_task_msg_check_param_t;
|
||
|
|
||
|
static uint32_t iot_task_msg_check(iot_msg_entry_t *msg, void* param)
|
||
|
{
|
||
|
iot_task_msg_check_param_t *check;
|
||
|
iot_task_msg_t *task_msg;
|
||
|
|
||
|
check = (iot_task_msg_check_param_t *)param;
|
||
|
task_msg = container_of(msg, iot_task_msg_t, link);
|
||
|
|
||
|
if (task_msg->type == check->type
|
||
|
&& (check->id == IOT_TASK_MSG_ID_ALL || task_msg->id == check->id)) {
|
||
|
msg->next = check->head;
|
||
|
check->head = msg;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void iot_task_clean_msg(iot_task_h task_h, uint16_t type, uint16_t id)
|
||
|
{
|
||
|
uint8_t i;
|
||
|
iot_msg_queue_t *pq;
|
||
|
iot_task_msg_t *task_msg;
|
||
|
iot_msg_entry_t *msg, *next_msg;
|
||
|
iot_task_msg_check_param_t param;
|
||
|
iot_task_t *task = (iot_task_t *)task_h;
|
||
|
|
||
|
param.head = NULL;
|
||
|
param.type = type;
|
||
|
param.id = id;
|
||
|
|
||
|
/* delete the message to be cleaned up from the message queue */
|
||
|
for (i = 0; i < task->cfg.queue_cnt; i++) {
|
||
|
pq = &task->msg_q[i].q;
|
||
|
iot_msg_queue_loop(pq, iot_task_msg_check, ¶m);
|
||
|
}
|
||
|
|
||
|
/* clean messages */
|
||
|
for (msg = param.head; msg != NULL; msg = next_msg) {
|
||
|
next_msg = msg->next;
|
||
|
task_msg = container_of(msg, iot_task_msg_t, link);
|
||
|
task->cfg.msg_cancel_func(task, task_msg);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
os_task_h IRAM_ATTR iot_task_get_os_task_h(iot_task_h task_h)
|
||
|
{
|
||
|
iot_task_t *task = (iot_task_t *)task_h;
|
||
|
return task->task_h;
|
||
|
}
|