/* * Copyright (c) 2022-2024, ArtInChip Technology Co., Ltd * * SPDX-License-Identifier: Apache-2.0 */ #ifndef _ARTINCHIP_AIC_OSAL_FREERTOS_H_ #define _ARTINCHIP_AIC_OSAL_FREERTOS_H_ #ifdef __cplusplus extern "C" { #endif #include #include #include #include //--------------------------------------------------------------------+ // Interrupt Define //--------------------------------------------------------------------+ static inline int aicos_in_irq(void) { return OSIntNesting; } //--------------------------------------------------------------------+ // Timeout Define //--------------------------------------------------------------------+ #define AICOS_WAIT_FOREVER (-1) //--------------------------------------------------------------------+ // Mem API //--------------------------------------------------------------------+ static inline void *aicos_malloc(unsigned int mem_type, size_t size) { return aic_tlsf_malloc(mem_type, size); } static inline void aicos_free(unsigned int mem_type, void *mem) { aic_tlsf_free(mem_type, mem); } static inline void *aicos_malloc_align(uint32_t mem_type, size_t size, size_t align) { return aic_tlsf_malloc_align(mem_type, size, align); } static inline void aicos_free_align(uint32_t mem_type, void *mem) { aic_tlsf_free_align(mem_type, mem); } static inline void *aicos_memdup(unsigned int mem_type, void *src, size_t size) { void *p; p = aic_tlsf_malloc(mem_type, size); if (p) memcpy(p, src, size); return p; } static inline void *aicos_memdup_align(unsigned int mem_type, void *src, size_t size, size_t align) { void *p; p = aic_tlsf_malloc_align(mem_type, size, align); if (p) memcpy(p, src, size); return p; } //--------------------------------------------------------------------+ // Thread API //--------------------------------------------------------------------+ static inline INT32U aicos_ucos_ms2tick(INT32U ms) { return ms * OS_TICKS_PER_SEC / 1000; } extern aicos_thread_t ucos_thread_array[]; /* Notes: * if any thread is created by 'aicos_thread_create', it must be deleted by 'aicos_thread_delete' * if any thread is created by 'OSTaskCreateExt' or 'OSTaskCreate', it must be deleted by 'OSTaskDel' */ static inline aicos_thread_t aicos_thread_create(const char *name, uint32_t stack_size, uint32_t prio, aic_thread_entry_t entry, void *args) { INT8U *stack_top_plus_regsize; OS_STK *stack; INT8U ret; stack_top_plus_regsize = aicos_malloc_align(MEM_DEFAULT, stack_size + sizeof(void *), sizeof(void *)); if (stack_top_plus_regsize == NULL) return NULL; *stack_top_plus_regsize = prio; stack = (OS_STK *)(stack_top_plus_regsize + sizeof(void *)); ret = OSTaskCreateExt(entry, args, (OS_STK *)(stack + stack_size), (INT8U)prio, (INT16U)prio, stack, stack_size / sizeof(OS_STK), NULL, OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR); if (ret != OS_ERR_NONE) { aicos_free(MEM_DEFAULT, stack_top_plus_regsize); return NULL; } ucos_thread_array[prio] = (aicos_thread_t)stack_top_plus_regsize; OSTaskNameSet(prio, (INT8U *)name, &ret); return (aicos_thread_t)stack_top_plus_regsize; } static inline void aicos_thread_delete(aicos_thread_t thread) { INT8U prio; INT8U *stack_top_plus_regsize; #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ OS_CPU_SR cpu_sr = 0u; #endif if (thread == NULL) { OS_ENTER_CRITICAL(); prio = OSTCBCur->OSTCBPrio; OS_EXIT_CRITICAL(); stack_top_plus_regsize = ucos_thread_array[prio]; } else { stack_top_plus_regsize = (INT8U *)thread - sizeof(void *); prio = *stack_top_plus_regsize; } /* OSTaskDel is unsafe... */ OSTaskDel(prio); ucos_thread_array[prio] = 0; aicos_free(MEM_DEFAULT, stack_top_plus_regsize); } static inline void aicos_thread_suspend(aicos_thread_t thread) { INT8U *prio; if (thread == NULL) return; prio = (INT8U *)thread - sizeof(void *); OSTaskSuspend(*prio); } static inline void aicos_thread_resume(aicos_thread_t thread) { INT8U *prio; if (thread == NULL) return; prio = (INT8U *)thread - sizeof(void *); OSTaskResume(*prio); } //--------------------------------------------------------------------+ // Counting Semaphore API //--------------------------------------------------------------------+ static inline aicos_sem_t aicos_sem_create(uint32_t initial_count) { return (aicos_sem_t)OSSemCreate(initial_count); } static inline void aicos_sem_delete(aicos_sem_t sem) { INT8U ret; OSSemDel((OS_EVENT *)sem, OS_DEL_NO_PEND, &ret); } static inline int aicos_sem_take(aicos_sem_t sem, uint32_t msec) { INT8U ret; INT32U tick; if (aicos_in_irq()) { return -EINVAL; } if (msec == AICOS_WAIT_FOREVER) { OSSemPend((OS_EVENT *)sem, 0, &ret); } else { tick = aicos_ucos_ms2tick(msec); if (tick == 0) return -EINVAL; OSSemPend((OS_EVENT *)sem, tick, &ret); } return (ret == OS_ERR_NONE) ? 0 : -ETIMEDOUT; } static inline int aicos_sem_give(aicos_sem_t sem) { INT8U ret; ret = OSSemPost((OS_EVENT *)sem); return (ret == OS_ERR_NONE) ? 0 : -EINVAL; } //--------------------------------------------------------------------+ // Mutex API (priority inheritance) //--------------------------------------------------------------------+ static inline aicos_mutex_t aicos_mutex_create(void) { INT8U err; return (aicos_mutex_t)OSMutexCreate(10, &err); } static inline void aicos_mutex_delete(aicos_mutex_t mutex) { INT8U err; OSMutexDel((OS_EVENT *)mutex, OS_DEL_NO_PEND, &err); } static inline int aicos_mutex_take(aicos_mutex_t mutex, uint32_t msec) { INT8U ret; INT32U tick; if (aicos_in_irq()) { return -EINVAL; } if (msec == AICOS_WAIT_FOREVER) { OSMutexPend((OS_EVENT *)mutex, 0, &ret); } else { tick = aicos_ucos_ms2tick(msec); if (tick == 0) return -EINVAL; OSMutexPend((OS_EVENT *)mutex, tick, &ret); } return (ret == OS_ERR_NONE) ? 0 : -ETIMEDOUT; } static inline int aicos_mutex_give(aicos_mutex_t mutex) { INT8U ret; ret = OSMutexPost((OS_EVENT *)mutex); return (ret == OS_ERR_NONE) ? 0 : -EINVAL; } //--------------------------------------------------------------------+ // Event API //--------------------------------------------------------------------+ static inline aicos_event_t aicos_event_create(void) { INT8U ret; return (aicos_event_t)OSFlagCreate(0, &ret); } static inline void aicos_event_delete(aicos_event_t event) { INT8U ret; OSFlagDel((OS_FLAG_GRP *)event, OS_DEL_NO_PEND, &ret); } static inline int aicos_event_recv(aicos_event_t event, uint32_t set, uint32_t *recved, uint32_t msec) { INT8U ret; INT32U tick; if (msec == AICOS_WAIT_FOREVER) { *recved = (uint32_t)OSFlagPend((OS_FLAG_GRP *)event, (OS_FLAGS)set, OS_FLAG_WAIT_SET_ANY, 0, &ret); } else { tick = aicos_ucos_ms2tick(msec); if (tick == 0) return -EINVAL; *recved = (uint32_t)OSFlagPend((OS_FLAG_GRP *)event, (OS_FLAGS)set, OS_FLAG_WAIT_SET_ANY, tick, &ret); } return (ret == OS_ERR_NONE) ? 0 : -EINVAL; } static inline int aicos_event_send(aicos_event_t event, uint32_t set) { INT8U ret; OSFlagPost((OS_FLAG_GRP *)event, set, OS_FLAG_SET, &ret); return (ret == OS_ERR_NONE) ? 0 : -EINVAL; } //--------------------------------------------------------------------+ // Queue API //--------------------------------------------------------------------+ typedef struct { void *mem; /* payload memory */ OS_MEM *mem_pool; /* payload pool */ OS_EVENT *qcb; /* ucos queue control block */ void **qcb_pool; /* ucos qcb pool */ uint32_t item_size; /* item size */ } ucos_qm_t; static inline aicos_queue_t aicos_queue_create(uint32_t item_size, uint32_t queue_size) { ucos_qm_t *qm; INT8U ret; // todo: is item_size nessery to be aligned? qm = aicos_malloc(MEM_DEFAULT, sizeof(ucos_qm_t)); if (!qm) return NULL; qm->mem = aicos_malloc(MEM_DEFAULT, item_size * queue_size); if (!qm->mem) { aicos_free(MEM_DEFAULT, qm); return NULL; } qm->qcb_pool = aicos_malloc(MEM_DEFAULT, queue_size * sizeof(void *)); if (!qm->qcb_pool) { aicos_free(MEM_DEFAULT, qm->mem); aicos_free(MEM_DEFAULT, qm); return NULL; } qm->mem_pool = OSMemCreate(qm->mem, queue_size, item_size, &ret); if (ret != OS_ERR_NONE) { aicos_free(MEM_DEFAULT, qm->qcb_pool); aicos_free(MEM_DEFAULT, qm->mem); aicos_free(MEM_DEFAULT, qm); } qm->qcb = OSQCreate(qm->qcb_pool, queue_size); if (!qm->qcb) { aicos_free(MEM_DEFAULT, qm->qcb_pool); aicos_free(MEM_DEFAULT, qm->mem); aicos_free(MEM_DEFAULT, qm); } qm->item_size = item_size; return (aicos_queue_t)qm; } static inline void aicos_queue_delete(aicos_queue_t queue) { ucos_qm_t *qm = (ucos_qm_t *)queue; INT8U ret; if (queue == NULL) return; OSQDel(qm->qcb, OS_DEL_NO_PEND, &ret); aicos_free(MEM_DEFAULT, qm->qcb_pool); aicos_free(MEM_DEFAULT, qm->mem); aicos_free(MEM_DEFAULT, qm); } static inline int aicos_queue_send(aicos_queue_t queue, void const *buff) { ucos_qm_t *qm = (ucos_qm_t *)queue; INT8U ret; void *mem_temp; if ((queue == NULL) || (buff == NULL)) return -EINVAL; mem_temp = OSMemGet(qm->mem_pool, &ret); if (ret != OS_ERR_NONE || mem_temp == NULL) { return -ENOMEM; } memcpy(mem_temp, buff, qm->item_size); ret = OSQPost(qm->qcb, mem_temp); if (ret != OS_ERR_NONE) { OSMemPut(qm->mem_pool, mem_temp); return -EINVAL; } return 0; } static inline int aicos_queue_receive(aicos_queue_t queue, void *buff, uint32_t msec) { ucos_qm_t *qm = (ucos_qm_t *)queue; INT8U ret; void *mem_temp; INT32U tick; if ((queue == NULL) || (buff == NULL)) return -EINVAL; if (msec == AICOS_WAIT_FOREVER) { tick = 0; } else { tick = aicos_ucos_ms2tick(msec); if (tick == 0) return -EINVAL; } mem_temp = OSQPend(qm->qcb, tick, &ret); if ((ret != OS_ERR_NONE) || (mem_temp == NULL)) { return -ETIMEDOUT; } memcpy(buff, mem_temp, qm->item_size); OSMemPut(qm->mem_pool, mem_temp); return 0; } static inline int aicos_queue_empty(aicos_queue_t queue) { OS_Q_DATA q_data; ucos_qm_t *qm = (ucos_qm_t *)queue; INT8U ret; if (queue == NULL) return -EINVAL; ret = OSQQuery(qm->qcb, &q_data); if (OS_ERR_NONE != ret) { return -EINVAL; } return (q_data.OSNMsgs == 0); } //--------------------------------------------------------------------+ // Wait Queue API //--------------------------------------------------------------------+ typedef struct { unsigned int set; aicos_event_t event; }osal_wqueue_def_t; typedef osal_wqueue_def_t* osal_wqueue_t; static inline aicos_wqueue_t aicos_wqueue_create(void) { osal_wqueue_t wqueue; wqueue = aicos_malloc(0, sizeof(osal_wqueue_t)); if (NULL == wqueue) return NULL; wqueue->event = aicos_event_create(); wqueue->set = 0; return (aicos_wqueue_t)wqueue; } static inline void aicos_wqueue_delete(aicos_wqueue_t wqueue) { osal_wqueue_t wq = (osal_wqueue_t)wqueue; aicos_event_t event = (aicos_event_t)wq->event; aicos_event_delete(event); aicos_free(0, wq); } static inline void aicos_wqueue_wakeup(aicos_wqueue_t wqueue) { osal_wqueue_t wq = (osal_wqueue_t)wqueue; aicos_event_t event = (aicos_event_t)wq->event; if (wq->set != 1) return; wq->set = 0; aicos_event_send(event, 0x1); } static inline int aicos_wqueue_wait(aicos_wqueue_t wqueue, uint32_t msec) { osal_wqueue_t wq = (osal_wqueue_t)wqueue; aicos_event_t event = (aicos_event_t)wq->event; uint32_t recved; wq->set = 1; return aicos_event_recv(event, 0x1, &recved, 100); } //--------------------------------------------------------------------+ // Critical API //--------------------------------------------------------------------+ static inline size_t aicos_enter_critical_section(void) { return OS_CPU_SR_Save(); } static inline void aicos_leave_critical_section(size_t flag) { OS_CPU_SR_Restore(flag); } //--------------------------------------------------------------------+ // Sleep API //--------------------------------------------------------------------+ static inline void aicos_msleep(uint32_t delay) { OSTimeDly(aicos_ucos_ms2tick(delay)); } #ifdef __cplusplus } #endif #endif