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;
 | |
| }
 |