/** ******************************************************************************* * @brief Initialize OS * @param[in] None * @param[out] None * @retval None * * @par Description * @details This function is called to initialize OS. * * @note You must call this function first,before any other OS API function * * @code There is a example for useage of this function,as follows: * e.g. * ... // Your target initial code. * * OsInit(); // Initial OS. * CreateTask(...); // Create tasks. * ... * OsStart(); // Start multitask. * @endcode ******************************************************************************* */ void CoInitOS(void) { InitSysTick(); /* Initialize system tick. */ InitInt(); /* Initialize PendSV,SVC,SysTick interrupt */ CreateTCBList(); /* Create TCB list. */ #if CFG_EVENT_EN > 0 CreateEventList(); /* Create event control list. */ #endif #if CFG_KHEAP_EN > 0 CoCreateKheap(); /* Create kernel heap within user define */ #endif OsSchedLock(); /* Lock Schedule */ /* Create first task -- IDLE task. */ CoCreateTask( CoIdleTask, Co_NULL, CFG_LOWEST_PRIO, &idle_stk[CFG_IDLE_STACK_SIZE-1], CFG_IDLE_STACK_SIZE ); /* Set PSP for CoIdleTask coming in */ SetEnvironment(&idle_stk[CFG_IDLE_STACK_SIZE-1]); }
/** ******************************************************************************* * @brief Reset task delay ticks * @param[in] ptcb Task that want to insert into DELAY list. * @param[in] ticks Specify system tick number which will delay . * @param[out] None * @retval E_CALL Error call in ISR. * @retval E_INVALID_ID Invalid task id. * @retval E_NOT_IN_DELAY_LIST Task not in delay list. * @retval E_OK The current task was inserted to DELAY list * successful,it will delay for specify time. * @par Description * @details This function delay specify ticks for current task. ******************************************************************************* */ StatusType CoResetTaskDelayTick(OS_TID taskID,U32 ticks) { P_OSTCB ptcb; #if CFG_PAR_CHECKOUT_EN >0 /* Check validity of parameter */ if(taskID >= CFG_MAX_USER_TASKS + SYS_TASK_NUM) { return E_INVALID_ID; } #endif ptcb = &TCBTbl[taskID]; #if CFG_PAR_CHECKOUT_EN >0 if(ptcb->stkPtr == Co_NULL) { return E_INVALID_ID; } #endif if(ptcb->delayTick == INVALID_VALUE) /* Is tick==INVALID_VALUE? */ { return E_NOT_IN_DELAY_LIST; /* Yes,error return */ } OsSchedLock(); /* Lock schedule */ RemoveDelayList(ptcb); /* Remove task from the DELAY list */ if(ticks == 0) /* Is delay tick==0? */ { InsertToTCBRdyList(ptcb); /* Insert task into the DELAY list */ } else { InsertDelayList(ptcb,ticks); /* No,insert task into DELAY list */ } OsSchedUnlock(); /* Unlock schedule,and call task schedule */ return E_OK; /* Return OK */ }
/** ******************************************************************************* * @brief Post a mail to queue * @param[in] id Event ID. * @param[in] pmail Pointer to mail that want to send. * @param[out] None * @retval E_OK * @retval E_INVALID_ID * @retval E_QUEUE_FULL * * @par Description * @details This function is called to post a mail to queue. * @note ******************************************************************************* */ StatusType CoPostQueueMail(OS_EventID id,void* pmail) { P_ECB pecb; P_QCB pqcb; #if CFG_PAR_CHECKOUT_EN >0 if(id >= CFG_MAX_EVENT) { return E_INVALID_ID; } #endif pecb = &EventTbl[id]; #if CFG_PAR_CHECKOUT_EN >0 if(pecb->eventType != EVENT_TYPE_QUEUE) { return E_INVALID_ID; /* The event type isn't queue,return */ } #endif pqcb = (P_QCB)pecb->eventPtr; if(pqcb->qSize == pqcb->qMaxSize) /* If queue is full */ { return E_QUEUE_FULL; } else /* If queue is not full */ { OsSchedLock(); *(pqcb->qStart + pqcb->tail) = pmail; /* Insert message into queue */ pqcb->tail++; /* Update queue tail */ pqcb->qSize++; /* Update the number of messages in the queue */ if(pqcb->tail == pqcb->qMaxSize) /* Check queue tail */ { pqcb->tail = 0; } EventTaskToRdy(pecb); /* Check the event waiting list */ OsSchedUnlock(); return E_OK; } }
/** ******************************************************************************* * @brief Create a mutex * @param[in] None * @param[out] None * @retval E_CREATE_FAIL Create mutex fail. * @retval others Create mutex successful. * * @par Description * @details This function is called to create a mutex. * @note ******************************************************************************* */ OS_MutexID CoCreateMutex(void) { OS_MutexID id; P_MUTEX pMutex; OsSchedLock(); /* Assign a free mutex control block */ if(MutexFreeID < CFG_MAX_MUTEX ) { id = MutexFreeID++; OsSchedUnlock(); pMutex = &MutexTbl[id]; pMutex->hipriTaskID = INVALID_ID; pMutex->originalPrio = 0xff; pMutex->mutexFlag = MUTEX_FREE; /* Mutex is free,not was occupied */ pMutex->taskID = INVALID_ID; pMutex->waittingList = Co_NULL; return id; /* Return mutex ID */ } OsSchedUnlock(); return E_CREATE_FAIL; /* No free mutex control block */ }
/** ******************************************************************************* * @brief Accept a mailbox * @param[in] id Event ID. * @param[out] perr A pointer to error code. * @retval NULL * @retval A pointer to mailbox accepted. * * @par Description * @details This function is called to accept a mailbox. * @note ******************************************************************************* */ void* CoAcceptMail(OS_EventID id,StatusType* perr) { P_ECB pecb; void* pmail; #if CFG_PAR_CHECKOUT_EN >0 if(id >= CFG_MAX_EVENT) { *perr = E_INVALID_ID; /* Invalid 'id' */ return NULL; } #endif pecb = &EventTbl[id]; #if CFG_PAR_CHECKOUT_EN >0 if(pecb->eventType != EVENT_TYPE_MBOX)/* Invalid event control block type */ { *perr = E_INVALID_ID; return NULL; } #endif OsSchedLock(); if(pecb->eventCounter == 1) /* If there is already a message */ { *perr = E_OK; pmail = pecb->eventPtr; /* Get the message */ pecb->eventPtr = NULL; /* Clear the mailbox */ pecb->eventCounter = 0; OsSchedUnlock(); return pmail; /* Return the message received */ } else /* If the mailbox is empty */ { OsSchedUnlock(); *perr = E_MBOX_EMPTY; /* Mailbox is empty,return NULL */ return NULL; } }
/** ******************************************************************************* * @brief Delete a event * @param[in] pecb Pointer to event control block which will be deleted. * @param[in] opt Delete option. * @arg == OPT_DEL_ANYWAY Delete event always * @arg == OPT_DEL_NO_PEND Delete event only when no task pending on. * @param[out] None * @retval E_INVALID_PARAMETER Parameter passed is invalid,deleted fail. * @retval E_TASK_WAITTING These are one more tasks waitting event. * @retval E_OK Delete event control block successful. * * @par Description * @details This function is called to delete a event from the event wait list * use specify option. * * @note This is a internal function of Coocox CoOS,user can't call. ******************************************************************************* */ StatusType DeleteEvent(P_ECB pecb,U8 opt) { P_OSTCB ptcb; if(opt == OPT_DEL_NO_PEND) /* Do delete event when no task pend? */ { if(pecb->eventTCBList != NULL) /* Yes,is there task pend this event? */ { return E_TASK_WAITING; /* Yes,error return */ } else { ReleaseECB(pecb); /* No,release resource that event hold*/ } } else if(opt == OPT_DEL_ANYWAY) /* Do delete event anyway? */ { OsSchedLock(); /* Lock schedule */ while(pecb->eventTCBList != NULL) /* Is there task pend this event? */ { /* Yes,remove it */ ptcb = pecb->eventTCBList;/* Get first task in event waiting list */ if(ptcb->delayTick != INVALID_VALUE) /* Is task in delay list? */ { RemoveDelayList(ptcb); /* Yes,remove task from delay list */ } /* Set next item as event waiting list head */ pecb->eventTCBList = ptcb->waitNext; ptcb->waitNext = NULL; /* Clear link for event waiting list */ ptcb->eventID = INVALID_ID; /* Sign that not to use. */ InsertToTCBRdyList(ptcb); /* Insert task into ready list */ } OsSchedUnlock(); /* Unlock schedule */ ReleaseECB(pecb); /* Release resource that event hold */ } return E_OK; /* Return OK */ }
/** ******************************************************************************* * @brief Remove a timer from the timer list * @param[in] tmrID Specify ID for a timer which removed form timer list. * @param[out] None * @retval None * * @par Description * @details This function is called to remove a timer from the timer list. ******************************************************************************* */ static void RemoveTmrList(OS_TCID tmrID) { P_TmrCtrl pTmr; pTmr = &TmrTbl[tmrID]; OsSchedLock(); /* Lock schedule */ /* Is there only one item in timer list? */ if((pTmr->tmrPrev == NULL) && (pTmr->tmrNext == NULL)) { TmrList = NULL; /* Yes,set timer list as NULL */ } else if(pTmr->tmrPrev == NULL) /* Is the first item in timer list? */ { /* Yes,remove timer from list,and reset timer list */ TmrList = pTmr->tmrNext; TmrList->tmrPrev = NULL; pTmr->tmrNext->tmrCnt += pTmr->tmrCnt; pTmr->tmrNext = NULL; } else if(pTmr->tmrNext == NULL) /* Is the last item in timer list? */ { /* Yes,remove timer form list */ pTmr->tmrPrev->tmrNext = NULL; pTmr->tmrPrev = NULL; } else /* No, remove timer from list */ { pTmr->tmrPrev->tmrNext = pTmr->tmrNext; pTmr->tmrNext->tmrPrev = pTmr->tmrPrev; pTmr->tmrNext->tmrCnt += pTmr->tmrCnt; pTmr->tmrNext = NULL; pTmr->tmrPrev = NULL; } OsSchedUnlock(); /* Unlock schedule */ }
/** ******************************************************************************* * @brief Delete a memory partition * @param[in] mmID Specify memory partition that want to delete. * @param[out] None * @retval E_INVALID_ID The memory partition id passed was invalid,delete fail. * @retval E_OK Delete successful. * * @par Description * @details This function is called to Delete a memory partition. ******************************************************************************* */ StatusType CoDelMemoryPartition(OS_MMID mmID) { P_MM memCtl; #if CFG_PAR_CHECKOUT_EN >0 /* Check validity of parameter */ if(mmID >= CFG_MAX_MM) { return E_INVALID_ID; } if( ((1<<mmID)&MemoryIDVessel) == 0) { return E_INVALID_ID; } #endif OsSchedLock(); /* Lock schedule */ memCtl = &MemoryTbl[mmID]; /* Release memory control block */ MemoryIDVessel &= ~(1<<mmID); OsSchedUnlock(); /* Unlock schedule */ memCtl->memAddr = NULL; memCtl->freeBlock = NULL; memCtl->blockSize = 0; memCtl->blockNum = 0; return E_OK; /* Return OK */ }
/** ******************************************************************************* * @brief Post a semaphore * @param[in] id id of event control block associated with the desired semaphore. * @param[out] None * @retval E_INVALID_ID Parameter id passed was invalid event ID. * @retval E_SEM_FULL Semaphore full. * @retval E_OK Semaphore had post successful. * * @par Description * @details This function is called to post a semaphore to corresponding event. * * @note ******************************************************************************* */ StatusType CoPostSem(OS_EventID id) { P_ECB pecb; #if CFG_PAR_CHECKOUT_EN >0 if(id >= CFG_MAX_EVENT) { return E_INVALID_ID; } #endif pecb = &EventTbl[id]; #if CFG_PAR_CHECKOUT_EN >0 if(pecb->eventType != EVENT_TYPE_SEM) /* Invalid event control block type */ { return E_INVALID_ID; } #endif /* Make sure semaphore will not overflow */ if(pecb->eventCounter == pecb->initialEventCounter) { return E_SEM_FULL; /* The counter of Semaphore reach the max number*/ } OsSchedLock(); if(pecb->eventTCBList != Co_NULL) { EventTaskToRdy(pecb); OsSchedUnlock(); return E_OK; } pecb->eventCounter++; /* Increment semaphore count to register event */ EventTaskToRdy(pecb); /* Check semaphore event waiting list */ OsSchedUnlock(); return E_OK; }
/** ******************************************************************************* * @brief Delay current task for specify ticks number * @param[in] ticks Specify system tick number which will delay. * @param[out] None * @retval E_CALL Error call in ISR. * @retval E_OK The current task was insert to DELAY list successful,it * will delay specify time. * @par Description * @details This function delay specify ticks for current task. * * @note This function be called in ISR,do nothing and return immediately. ******************************************************************************* */ StatusType CoTickDelay(U32 ticks) { if(OSIntNesting >0) /* Is call in ISR? */ { return E_CALL; /* Yes,error return */ } if(ticks == INVALID_VALUE) /* Is tick==INVALID_VALUE? */ { return E_INVALID_PARAMETER; /* Yes,error return */ } if(ticks == 0) /* Is tick==0? */ { return E_OK; /* Yes,do nothing ,return OK */ } if(OSSchedLock != 0) /* Is OS lock? */ { return E_OS_IN_LOCK; /* Yes,error return */ } OsSchedLock(); /* Lock schedule */ InsertDelayList(TCBRunning,ticks); /* Insert task in DELAY list */ OsSchedUnlock(); /* Unlock schedule,and call task schedule */ return E_OK; /* Return OK */ }
/** ******************************************************************************* * @brief Lock schedule * @param[in] None * @param[out] None * @retval None * * @par Description * @details This function is called in application code to lock schedule. * * @note ******************************************************************************* */ void CoSchedLock(void) { OsSchedLock(); /* Lock schedule */ }
/** ******************************************************************************* * @brief Pend for a mail * @param[in] id Event ID. * @param[in] timeout The longest time for writting mail. * @param[out] perr A pointer to error code. * @retval NULL * @retval A pointer to mail accept. * * @par Description * @details This function is called to wait for a mail. * @note ******************************************************************************* */ void* CoPendQueueMail(OS_EventID id,U32 timeout,StatusType* perr) { P_ECB pecb; P_QCB pqcb; P_OSTCB curTCB; void* pmail; if(OSIntNesting > 0) /* If the caller is ISR */ { *perr = E_CALL; return NULL; } #if CFG_PAR_CHECKOUT_EN >0 if(id >= CFG_MAX_EVENT) { *perr = E_INVALID_ID; /* Invalid event id,return error */ return NULL; } #endif pecb = &EventTbl[id]; #if CFG_PAR_CHECKOUT_EN >0 if(pecb->eventType != EVENT_TYPE_QUEUE) /* The event type is not queue */ { *perr = E_INVALID_ID; return NULL; } #endif if(OSSchedLock != 0) /* Judge schedule is locked or not? */ { *perr = E_OS_IN_LOCK; /* Schedule is locked,return error */ return NULL; } pqcb = (P_QCB)pecb->eventPtr; /* Point at queue control block */ if(pqcb->qSize != 0) /* If there are any messages in the queue */ { /* Extract oldest message from the queue */ pmail = *(pqcb->qStart + pqcb->head); pqcb->head++; /* Update the queue head */ pqcb->qSize--; /* Update the number of messages in the queue */ if(pqcb->head == pqcb->qMaxSize)/* Check queue head */ { pqcb->head = 0; } *perr = E_OK; return pmail; /* Return message received */ } else /* If there is no message in the queue*/ { curTCB = TCBRunning; if(timeout == 0) /* If time-out is not configured */ { /* Block current task until the event occur */ EventTaskToWait(pecb,curTCB); /* Have recived message or the queue have been deleted */ pmail = curTCB->pmail; curTCB->pmail = NULL; *perr = E_OK; return pmail; /* Return message received or NULL */ } else /* If time-out is configured */ { OsSchedLock(); /* Block current task until event or timeout occurs */ EventTaskToWait(pecb,curTCB); InsertDelayList(curTCB,timeout); OsSchedUnlock(); if(curTCB->pmail == NULL) /* If time-out occurred */ { *perr = E_TIMEOUT; return NULL; } else /* If event occured */ { pmail = curTCB->pmail; curTCB->pmail = NULL; *perr = E_OK; return pmail; /* Return message received or NULL */ } } } }
/** ******************************************************************************* * @brief Insert a timer into the timer list * @param[in] tmrID Specify timer ID which insertted. * @param[out] None * @retval E_INVALID_ID Timer ID passed was invalid,insert fail. * @retval E_OK Insert successful. * * @par Description * @details This function is called to insert a timer into the timer list. ******************************************************************************* */ static void InsertTmrList(OS_TCID tmrID) { P_TmrCtrl pTmr; S32 deltaTicks; U32 tmrCnt; tmrCnt = TmrTbl[tmrID].tmrCnt; /* Get timer time */ if(tmrCnt == 0) /* Is timer time==0? */ { return; /* Do nothing,return */ } OsSchedLock(); /* Lock schedule */ if(TmrList == NULL) /* Is no item in timer list? */ { TmrList = &TmrTbl[tmrID]; /* Yes,set this as first item */ } else /* No,find correct place ,and insert inserted timer */ { pTmr = TmrList; deltaTicks = (S32) tmrCnt; /* Get timer tick */ /* find correct place */ while(pTmr != NULL) { deltaTicks -= (S32) (pTmr->tmrCnt); /* Get ticks with previous item */ if(deltaTicks < 0) /* Is delta ticks<0? */ { /* Yes,get correct place */ if(pTmr->tmrPrev!= NULL)/* Is head item of timer list? */ { /* No,insert into */ pTmr->tmrPrev->tmrNext = &TmrTbl[tmrID]; TmrTbl[tmrID].tmrPrev = pTmr->tmrPrev; TmrTbl[tmrID].tmrNext = pTmr; pTmr->tmrPrev = &TmrTbl[tmrID]; } else /* Yes,set task as first item */ { TmrTbl[tmrID].tmrNext = TmrList; TmrList->tmrPrev = &TmrTbl[tmrID]; TmrList = &TmrTbl[tmrID]; } TmrTbl[tmrID].tmrCnt = (U32)((S32)(TmrTbl[tmrID].tmrNext->tmrCnt) + deltaTicks); TmrTbl[tmrID].tmrNext->tmrCnt -= TmrTbl[tmrID].tmrCnt; break; } /* Is last item in list? */ else if ((deltaTicks >= 0) && (pTmr->tmrNext == NULL)) { /* Yes,insert into */ TmrTbl[tmrID].tmrPrev = pTmr; pTmr->tmrNext = &TmrTbl[tmrID]; TmrTbl[tmrID].tmrCnt = (U32) deltaTicks; break; } pTmr = pTmr->tmrNext; /* Get the next item in timer list */ } } OsSchedUnlock(); /* Unlock schedule */ }
/** ******************************************************************************* * @brief Change task priority * @param[in] taskID Specify task id. * @param[in] priority New priority. * @param[out] None * @retval E_OK Change priority successful. * @retval E_INVALID_ID Invalid id,change priority fail. * @retval E_PROTECTED_TASK Can't change idle task priority. * * @par Description * @details This function is called to change priority for a specify task. ******************************************************************************* */ StatusType CoSetPriority(OS_TID taskID,U8 priority) { P_OSTCB ptcb; #if CFG_MUTEX_EN >0 U8 prio; P_MUTEX pMutex; #endif #if CFG_EVENT_EN >0 P_ECB pecb; #endif if(taskID == 0) /* Is idle task? */ { return E_PROTECTED_TASK; /* Yes,error return */ } #if CFG_PAR_CHECKOUT_EN >0 /* Check validity of parameter */ if(taskID >= CFG_MAX_USER_TASKS + SYS_TASK_NUM) { return E_INVALID_ID; } #endif ptcb = &TCBTbl[taskID]; /* Get TCB of task ID */ #if CFG_PAR_CHECKOUT_EN >0 if(ptcb->state == TASK_DORMANT) { return E_INVALID_ID; } if(priority > CFG_LOWEST_PRIO) { return E_INVALID_ID; } #endif if(ptcb->prio != priority) /* Is PRI equal to original PRI? */ { /* No */ #if CFG_MUTEX_EN >0 if(ptcb->mutexID != INVALID_ID) { pMutex = &MutexTbl[ptcb->mutexID]; if(pMutex->taskID == ptcb->taskID) /* Task hold mutex? */ { pMutex->originalPrio= priority;/* Yes,change original PRI in mutex*/ if(ptcb->prio < priority) /* Is task priority higher than set?*/ { return E_OK; /* Yes,do nothing,return OK */ } } } #endif #if CFG_ORDER_LIST_SCHEDULE_EN ==0 DeleteTaskPri(ptcb->prio); ActiveTaskPri(priority); #endif ptcb->prio = priority; /* Change task PRI */ if(ptcb->state == TASK_READY) /* Is task in READY list? */ { OsSchedLock(); /* Yes,reorder task in READY list */ RemoveFromTCBRdyList(ptcb); InsertToTCBRdyList(ptcb); OsSchedUnlock(); } else if(ptcb->state == TASK_RUNNING)/* Is task running? */ { if(ptcb->prio > TCBRdy->prio) /* Yes,Is PRI higher than TCBRdy? */ { OsSchedLock(); /* Yes,reorder task in READY list */ TaskSchedReq = Co_TRUE; OsSchedUnlock(); } } else { /* No,task in WAITING list */ #if CFG_MUTEX_EN >0 if(ptcb->mutexID != INVALID_ID) /* Is task in mutex WAITING list? */ { /* Yes,reset the highest PRI in the list */ OsSchedLock(); pMutex = &MutexTbl[ptcb->mutexID]; ptcb = pMutex->waittingList; prio = pMutex->originalPrio; pMutex->hipriTaskID = pMutex->taskID; while(ptcb != Co_NULL) { if(ptcb->prio < prio) { prio = ptcb->prio; pMutex->hipriTaskID = ptcb->taskID; } ptcb = ptcb->TCBnext; } OsSchedUnlock(); if(pMutex->originalPrio != prio) { CoSetPriority(pMutex->taskID,prio); } } #endif #if CFG_EVENT_EN >0 ptcb = &TCBTbl[taskID]; if(ptcb->eventID != INVALID_ID) /* Is task in event WAITING list? */ { pecb = &EventTbl[ptcb->eventID]; /* Yes,is event sort type as preemptive PRI? */ if(pecb->eventSortType == EVENT_SORT_TYPE_PRIO) { /* Yes,reorder task in the list */ RemoveEventWaittingList(ptcb); EventTaskToWait(pecb,ptcb); } } #endif } } return E_OK; }
/** ******************************************************************************* * @brief Leave from a critical area * @param[in] mutexID Specify mutex id. * @param[out] None * @retval E_INVALID_ID Invalid mutex id. * @retval E_CALL Error call in ISR. * @retval E_OK Exit a critical area successful. * * @par Description * @details This function must be called when exiting from a critical area. * @note ******************************************************************************* */ StatusType CoLeaveMutexSection(OS_MutexID mutexID) { P_OSTCB ptcb; P_MUTEX pMutex; U8 prio; U8 taskID; if(OSIntNesting > 0) /* If the caller is ISR */ { return E_CALL; } #if CFG_PAR_CHECKOUT_EN >0 if(mutexID >= MutexFreeID) { return E_INVALID_ID; /* Invalid mutex id, return error */ } #endif OsSchedLock(); pMutex = &MutexTbl[mutexID]; /* Obtain point of mutex control block*/ ptcb = &TCBTbl[pMutex->taskID]; ptcb->mutexID = INVALID_ID; if(pMutex->waittingList == Co_NULL) /* If the mutex waiting list is empty */ { pMutex->mutexFlag = MUTEX_FREE; /* The mutex resource is available */ pMutex->taskID = INVALID_ID; OsSchedUnlock(); } else /* If there is at least one task waitting for the mutex */ { taskID = pMutex->taskID; /* Get task ID of mutex owner */ /* we havn't promoted current task's priority */ if(pMutex->hipriTaskID == taskID) { ptcb = pMutex->waittingList;/* Point to mutex first waiting task */ prio = ptcb->prio; while(ptcb != Co_NULL) /* Find the highest priority task */ { if(ptcb->prio < prio) { prio = ptcb->prio; pMutex->hipriTaskID = ptcb->taskID; } ptcb = ptcb->TCBnext; } } else /* we have promoted current task's priority */ { prio = TCBTbl[taskID].prio; } /* Reset the task priority */ pMutex->taskID = INVALID_ID; CoSetPriority(taskID,pMutex->originalPrio); /* Find first task in waiting list ready to run */ ptcb = pMutex->waittingList; pMutex->waittingList = ptcb->TCBnext; pMutex->originalPrio = ptcb->prio; pMutex->taskID = ptcb->taskID; #if CFG_ORDER_LIST_SCHEDULE_EN ==0 if(prio != ptcb->prio) { DeleteTaskPri(ptcb->prio); ActiveTaskPri(prio); } #endif ptcb->prio = prio; /* Raise the task's priority */ /* Insert the task which acquire the mutex into ready list. */ ptcb->TCBnext = Co_NULL; ptcb->TCBprev = Co_NULL; InsertToTCBRdyList(ptcb); /* Insert the task into the READY list */ OsSchedUnlock(); } return E_OK; }
/** ******************************************************************************* * @brief Enter a critical area * @param[in] mutexID Specify mutex. * @param[out] None * @retval E_INVALID_ID Invalid mutex id. * @retval E_CALL Error call in ISR. * @retval E_OK Enter critical area successful. * * @par Description * @details This function is called when entering a critical area. * @note ******************************************************************************* */ StatusType CoEnterMutexSection(OS_MutexID mutexID) { P_OSTCB ptcb,pCurTcb; P_MUTEX pMutex; #if CFG_EVENT_EN >0 P_ECB pecb; #endif if(OSIntNesting > 0) /* If the caller is ISR */ { return E_CALL; } if(OSSchedLock != 0) /* Is OS lock? */ { return E_OS_IN_LOCK; /* Yes,error return */ } #if CFG_PAR_CHECKOUT_EN >0 if(mutexID >= MutexFreeID) /* Invalid 'mutexID' */ { return E_INVALID_ID; } #endif OsSchedLock(); pCurTcb = TCBRunning; pMutex = &MutexTbl[mutexID]; pCurTcb->mutexID = mutexID; if(pMutex->mutexFlag == MUTEX_FREE) /* If mutex is available */ { pMutex->originalPrio = pCurTcb->prio; /* Save priority of owning task */ pMutex->taskID = pCurTcb->taskID; /* Acquire the resource */ pMutex->hipriTaskID = pCurTcb->taskID; pMutex->mutexFlag = MUTEX_OCCUPY; /* Occupy the mutex resource*/ } /* If the mutex resource had been occupied */ else if(pMutex->mutexFlag == MUTEX_OCCUPY) { ptcb = &TCBTbl[pMutex->taskID]; if(ptcb->prio > pCurTcb->prio) /* Need to promote priority of owner? */ { #if CFG_ORDER_LIST_SCHEDULE_EN ==0 DeleteTaskPri(ptcb->prio); ActiveTaskPri(pCurTcb->prio); #endif ptcb->prio = pCurTcb->prio; /* Promote prio of owner */ /* Upgarde the highest priority about the mutex */ pMutex->hipriTaskID = pCurTcb->taskID; if(ptcb->state == TASK_READY) /* If the task is ready to run */ { RemoveFromTCBRdyList(ptcb); /* Remove the task from READY list*/ InsertToTCBRdyList(ptcb); /* Insert the task into READY list*/ } #if CFG_EVENT_EN >0 /* If the task is waiting on a event */ else if(ptcb->eventID != INVALID_ID) { pecb = &EventTbl[ptcb->eventID]; /* If the event waiting type is preemptive Priority */ if(pecb->eventSortType == EVENT_SORT_TYPE_PRIO) { /* Remove the task from event waiting list */ RemoveEventWaittingList(ptcb); /* Insert the task into event waiting list */ EventTaskToWait(pecb,ptcb); } } #endif } pCurTcb->state = TASK_WAITING; /* Block current task */ TaskSchedReq = Co_TRUE; pCurTcb->TCBnext = Co_NULL; pCurTcb->TCBprev = Co_NULL; ptcb = pMutex->waittingList; if(ptcb == Co_NULL) /* If the event waiting list is empty */ { pMutex->waittingList = pCurTcb; /* Insert the task to head */ } else /* If the event waiting list is not empty */ { while(ptcb->TCBnext != Co_NULL) /* Insert the task to tail */ { ptcb = ptcb->TCBnext; } ptcb->TCBnext = pCurTcb; pCurTcb->TCBprev = ptcb; pCurTcb->TCBnext = Co_NULL; } } OsSchedUnlock(); return E_OK; }
/** ******************************************************************************* * @brief wait for a semaphore * @param[in] id Event ID. * @param[in] timeout The longest time for writting semaphore. * @para 0 * @para 0x1~0xff * @param[out] None * @retval E_CALL Error call in ISR. * @retval E_INVALID_ID Invalid event ID. * @retval E_TIMEOUT Semaphore was not received within the specified * 'timeout' time. * @retval E_OK The call was successful and your task owns the * resource,or the event you are waiting for occurred. * * @par Description * @details This function is called to waits for a semaphore. * @note IF this function is called in ISR,nothing to do and return immediately. ******************************************************************************* */ StatusType CoPendSem(OS_EventID id,U32 timeout) { P_ECB pecb; P_OSTCB curTCB; if(OSIntNesting > 0) /* If the caller is ISR */ { return E_CALL; } #if CFG_PAR_CHECKOUT_EN >0 if(id >= CFG_MAX_EVENT) { return E_INVALID_ID; } #endif pecb = &EventTbl[id]; #if CFG_PAR_CHECKOUT_EN >0 if(pecb->eventType != EVENT_TYPE_SEM) { return E_INVALID_ID; } #endif if(OSSchedLock != 0) /* Schdule is locked? */ { return E_OS_IN_LOCK; /* Yes,error return */ } OsSchedLock(); if(pecb->eventCounter > 0) /* If semaphore is positive,resource available */ { pecb->eventCounter--; /* Decrement semaphore only if positive */ OsSchedUnlock(); return E_OK; } else /* Resource is not available */ { curTCB = TCBRunning; if(timeout == 0) /* If time-out is not configured */ { EventTaskToWait(pecb,curTCB); /* Block task until event occurs */ pecb->eventCounter--; curTCB->pmail = Co_NULL; OsSchedUnlock(); return E_OK; } else /* If time-out is configured */ { /* Block task until event or timeout occurs */ EventTaskToWait(pecb,curTCB); InsertDelayList(curTCB,timeout); OsSchedUnlock(); if (curTCB->pmail == Co_NULL) /* If pmail is Co_NULL, time-out occurred*/ { return E_TIMEOUT; } else /* Event occurred or event have been deleted*/ { OsSchedLock(); curTCB->pmail = Co_NULL; pecb->eventCounter--; OsSchedUnlock(); return E_OK; } } } }
/** ******************************************************************************* * @brief Wait for a mailbox * @param[in] id Event ID. * @param[in] timeout The longest time for writting mail. * @param[out] perr A pointer to error code. * @retval NULL * @retval A pointer to mailbox accept. * * @par Description * @details This function is called to wait a mailbox. * @note ******************************************************************************* */ void* CoPendMail(OS_EventID id,U32 timeout,StatusType* perr) { P_ECB pecb; void* pmail; P_OSTCB curTCB; if(OSIntNesting > 0) /* If the caller is ISR */ { *perr = E_CALL; return NULL; } #if CFG_PAR_CHECKOUT_EN >0 if(id >= CFG_MAX_EVENT) { *perr = E_INVALID_ID; /* Invalid 'id',retrun error */ return NULL; } #endif pecb = &EventTbl[id]; #if CFG_PAR_CHECKOUT_EN >0 if(pecb->eventType != EVENT_TYPE_MBOX) { *perr = E_INVALID_ID; /* Invalid event type,not EVENT_TYPE_MBOX */ return NULL; } #endif if(OSSchedLock != 0) /* Judge schedule is locked or not? */ { *perr = E_OS_IN_LOCK; /* Schedule is locked */ return NULL; /* return NULL */ } if( pecb->eventCounter == 1) /* If there is already a message */ { *perr = E_OK; pmail = pecb->eventPtr; /* Get the message */ pecb->eventPtr = NULL; /* Clear the mailbox */ pecb->eventCounter = 0; return pmail; /* Return the message received */ } else /* If message is not available, task will pend */ { curTCB = TCBRunning; if(timeout == 0) /* If time-out is not configured */ { EventTaskToWait(pecb,curTCB); /* Block task until event occurs */ *perr = E_OK; /* Have recived a message or the mailbox have been deleted */ pmail = curTCB->pmail; curTCB->pmail = NULL; return pmail; /* Return received message or NULL */ } else /* If time-out is configured */ { OsSchedLock(); /* Block task until event or timeout occurs */ EventTaskToWait(pecb,curTCB); InsertDelayList(curTCB,timeout); OsSchedUnlock(); if( curTCB->pmail == NULL) /* Time-out occurred */ { *perr = E_TIMEOUT; return NULL; } else /* Have recived a message or the mailbox have been deleted*/ { *perr = E_OK; pmail = curTCB->pmail; curTCB->pmail = NULL; return pmail; /* Return received message or NULL */ } } } }
/** ******************************************************************************* * @brief WaitForSingleFlag * @param[in] id Flag ID. * @param[in] timeout The longest time for writting flag. * @param[out] None * @retval E_CALL Error call in ISR. * @retval E_INVALID_ID Invalid event ID. * @retval E_TIMEOUT Flag wasn't received within 'timeout' time. * @retval E_OK The call was successful and your task owns the Flag, * or the event you are waiting for occurred. * * @par Description * @details This function is called to wait for only one flag, * (1) if parameter "timeout" == 0,waiting until flag be set; * (2) when "timeout" != 0,if flag was set or wasn't set but timeout * occured,the task will exit the waiting list,convert to READY * or RUNNING state. * @note ******************************************************************************* */ StatusType CoWaitForSingleFlag(OS_FlagID id,U32 timeout) { FLAG_NODE flagNode; P_FCB pfcb; P_OSTCB curTCB; if(OSIntNesting > 0) /* See if the caller is ISR */ { return E_CALL; } if(OSSchedLock != 0) /* Schedule is lock? */ { return E_OS_IN_LOCK; /* Yes,error return */ } #if CFG_PAR_CHECKOUT_EN >0 if(id >= FLAG_MAX_NUM) /* Judge id is valid or not? */ { return E_INVALID_ID; /* Invalid 'id' */ } if((FlagCrl.flagActive&(1<<id)) == 0 )/* Judge flag is active or not? */ { return E_INVALID_ID; /* Flag is deactive ,return error */ } #endif OsSchedLock(); pfcb = &FlagCrl; /* See if the required flag is set */ if((pfcb->flagRdy&(1<<id)) != 0) /* If the required flag is set */ { pfcb->flagRdy &= ~((pfcb->resetOpt&(1<<id))); /* Clear the flag */ OsSchedUnlock(); } else /* If the required flag is not set */ { curTCB = TCBRunning; if(timeout == 0) /* If time-out is not configured */ { /* Block task until the required flag is set */ FlagBlock (&flagNode,(1<<id),OPT_WAIT_ONE); curTCB->state = TASK_WAITING; TaskSchedReq = Co_TRUE; OsSchedUnlock(); /* The required flag is set and the task is in running state */ curTCB->pnode = Co_NULL; OsSchedLock(); /* Clear the required flag or not */ pfcb->flagRdy &= ~((1<<id)&(pfcb->resetOpt)); OsSchedUnlock(); } else /* If time-out is configured */ { /* Block task until the required flag is set or time-out occurs */ FlagBlock(&flagNode,(1<<id),OPT_WAIT_ONE); InsertDelayList(curTCB,timeout); OsSchedUnlock(); if(curTCB->pnode == Co_NULL) /* If time-out occurred */ { return E_TIMEOUT; } else /* If flag is set */ { curTCB->pnode = Co_NULL; OsSchedLock(); /* Clear the required flag or not */ pfcb->flagRdy &= ~((1<<id)&(pfcb->resetOpt)); OsSchedUnlock(); } } } return E_OK; }
/** ******************************************************************************* * @brief Insert a task to event wait list * @param[in] pecb Pointer to event control block corresponding to the event. * @param[in] ptcb Pointer to task that will be insert to event wait list. * @param[out] None * @retval None * * @par Description * @details This function is called to insert a task by fllowing manner: * opt == EVENT_SORT_TYPE_FIFO By FIFO. * opt == EVENT_SORT_TYPE_PRIO By priority order,hghest priority * as head,lowest priority as end. * (Highest-->...-->Lowest-->NULL) ******************************************************************************* */ void EventTaskToWait(P_ECB pecb,P_OSTCB ptcb) { P_OSTCB ptcb1; #if (CFG_EVENT_SORT == 2) || (CFG_EVENT_SORT == 3) P_OSTCB ptcb2; #endif OsSchedLock(); /* Lock schedule */ ptcb1 = pecb->eventTCBList; /* Get first task in event waiting list */ ptcb->eventID = pecb->id; /* Set event ID for task */ #if CFG_EVENT_SORT == 3 /* Does event waiting list sort as FIFO? */ if(pecb->eventSortType == EVENT_SORT_TYPE_FIFO) #endif #if (CFG_EVENT_SORT == 1) || (CFG_EVENT_SORT == 3) { if(ptcb1 == NULL) /* Is no item in event waiting list?*/ { pecb->eventTCBList = ptcb; /* Yes,set task as first item */ } else { while(ptcb1->waitNext != NULL)/* No,insert task in last */ { ptcb1 = ptcb1->waitNext; } ptcb1->waitNext = ptcb; /* Set link for list */ ptcb->waitPrev = ptcb1; } } #endif #if CFG_EVENT_SORT ==3 /* Does event waiting list sort as preemptive priority?*/ else if(pecb->eventSortType == EVENT_SORT_TYPE_PRIO) #endif #if (CFG_EVENT_SORT == 2) || (CFG_EVENT_SORT == 3) { if(ptcb1 == NULL) /* Is no item in event waiting list? */ { pecb->eventTCBList = ptcb; /* Yes,set task as first item */ } /* Is PRI of task higher than list first item? */ else if(ptcb1->prio > ptcb->prio) { pecb->eventTCBList = ptcb; /* Reset task as first item */ ptcb->waitNext = ptcb1; /* Set link for list */ ptcb1->waitPrev = ptcb; } else /* No,find correct place to insert */ { ptcb2 = ptcb1->waitNext; while(ptcb2 != NULL) /* Is last item? */ { if(ptcb2->prio > ptcb->prio) /* No,is correct place? */ { break; /* Yes,break Circulation */ } ptcb1 = ptcb2; /* Save current item */ ptcb2 = ptcb2->waitNext; /* Get next item */ } ptcb1->waitNext = ptcb; /* Set link for list */ ptcb->waitPrev = ptcb1; ptcb->waitNext = ptcb2; if(ptcb2 != NULL) { ptcb2->waitPrev = ptcb; } } } #endif ptcb->state = TASK_WAITING; /* Set task status to TASK_WAITING state */ TaskSchedReq = TRUE; OsSchedUnlock(); /* Unlock schedule,and call task schedule */ }
/** ******************************************************************************* * @brief Create a task * @param[in] task Task code entry. * @param[in] argv The parameter passed to task. * @param[in] parameter Task priority + stack size + time slice + isWaitting. * @param[in] stk Pointer to stack top of task. * @param[out] None * @retval E_CREATE_FAIL Fail to create a task . * @retval others Valid task id. * * @par Description * @details This function is called by application to create a task,return a id * to mark this task. ******************************************************************************* */ OS_TID CreateTask(FUNCPtr task,void *argv,U32 parameter,OS_STK *stk) { OS_STK* stkTopPtr; P_OSTCB ptcb; U8 prio; #if CFG_ROBIN_EN >0 U16 timeSlice; #endif #if CFG_STK_CHECKOUT_EN >0 /* Check validity of parameter */ U16 sktSz; sktSz = (parameter&0xfff00)>>8; #endif prio = parameter&0xff; #if CFG_PAR_CHECKOUT_EN >0 /* Check validity of parameter */ if(task == Co_NULL) { return E_CREATE_FAIL; } if(stk == Co_NULL) { return E_CREATE_FAIL; } if(prio > CFG_LOWEST_PRIO) { return E_CREATE_FAIL; } #if CFG_STK_CHECKOUT_EN >0 if(sktSz < 20) { return E_CREATE_FAIL; } #endif // CFG_STK_CHECKOUT_EN #endif // CFG_PAR_CHECKOUT_EN #if CFG_TASK_SCHEDULE_EN == 0 if(TCBRunning != Co_NULL) return E_CREATE_FAIL; #endif stkTopPtr = InitTaskContext(task,argv,stk); /* Initialize task context. */ ptcb = AssignTCB(); /* Get free TCB to use */ if(ptcb == Co_NULL) /* Is free TCB equal to Co_NULL? */ { return E_CREATE_FAIL; /* Yes,error return */ } ptcb->stkPtr = stkTopPtr; /* Initialize TCB as user set */ ptcb->prio = prio; #if CFG_STK_CHECKOUT_EN >0 ptcb->stack = stk+1 - sktSz; /* Set bottom stack for stack overflow check */ *(U32*)(ptcb->stack) = MAGIC_WORD; #endif #if CFG_TASK_WAITTING_EN >0 ptcb->delayTick = INVALID_VALUE; #endif #if CFG_TASK_SCHEDULE_EN == 0 ptcb->taskFuc = task; ptcb->taskStk = stk; #endif ptcb->TCBnext = Co_NULL; /* Initialize TCB link in READY list */ ptcb->TCBprev = Co_NULL; #if CFG_ROBIN_EN >0 /* Set task time slice for task robin */ timeSlice = (parameter&0x7fff0000)>>20; if(timeSlice == 0) { timeSlice = CFG_TIME_SLICE; } ptcb->timeSlice = timeSlice; #endif #if CFG_FLAG_EN > 0 ptcb->pnode = Co_NULL; /* Initialize task as no flag waiting */ #endif #if CFG_EVENT_EN > 0 ptcb->eventID = INVALID_ID; /* Initialize task as no event waiting*/ ptcb->pmail = Co_NULL; ptcb->waitNext = Co_NULL; ptcb->waitPrev = Co_NULL; #endif #if CFG_MUTEX_EN > 0 /* Initialize task as no mutex holding or waiting */ ptcb->mutexID = INVALID_ID; #endif #if CFG_ORDER_LIST_SCHEDULE_EN ==0 ActiveTaskPri(prio); #endif if((parameter>>31) == 0) /* Is task in waitting state? */ { /* No,set it into ready list */ OsSchedLock(); /* Lock schedule */ InsertToTCBRdyList(ptcb); /* Insert into the READY list */ OsSchedUnlock(); /* Unlock schedule */ } else { /* Yes,Set task status as TASK_WAITING*/
/** ******************************************************************************* * @brief WaitForMultipleFlags * @param[in] flags Flags that waiting to active task. * @param[in] waitType Flags wait type. * @param[in] timeout The longest time for writting flag. * @param[out] perr A pointer to error code. * @retval 0 * @retval springFlag * * @par Description * @details This function is called to pend a task for waitting multiple flag. * @note ******************************************************************************* */ U32 CoWaitForMultipleFlags(U32 flags,U8 waitType,U32 timeout,StatusType *perr) { U32 springFlag; P_FCB pfcb; FLAG_NODE flagNode; P_OSTCB curTCB; if(OSIntNesting > 0) /* If the caller is ISR */ { *perr = E_CALL; return 0; } if(OSSchedLock != 0) /* Schedule is lock? */ { *perr = E_OS_IN_LOCK; return 0; /* Yes,error return */ } #if CFG_PAR_CHECKOUT_EN >0 if( (flags&FlagCrl.flagActive) != flags ) { *perr = E_INVALID_PARAMETER; /* Invalid 'flags' */ return 0; } #endif OsSchedLock(); pfcb = &FlagCrl; springFlag = flags & pfcb->flagRdy; /* If any required flags are set */ if((springFlag != 0) && (waitType == OPT_WAIT_ANY)) { pfcb->flagRdy &= ~(springFlag & pfcb->resetOpt); /* Clear the flag */ OsSchedUnlock(); *perr = E_OK; return springFlag; } /* If all required flags are set */ if( (springFlag == flags) && (waitType == OPT_WAIT_ALL) ) { pfcb->flagRdy &= ~(springFlag & pfcb->resetOpt); /* Clear the flags */ OsSchedUnlock(); *perr = E_OK; return springFlag; } curTCB = TCBRunning; if(timeout == 0) /* If time-out is not configured */ { /* Block task until the required flag are set */ FlagBlock(&flagNode,flags,waitType); curTCB->state = TASK_WAITING; TaskSchedReq = Co_TRUE; OsSchedUnlock(); curTCB->pnode = Co_NULL; OsSchedLock(); springFlag = flags & pfcb->flagRdy; pfcb->flagRdy &= ~(springFlag & pfcb->resetOpt);/* Clear the flags */ OsSchedUnlock(); *perr = E_OK; return springFlag; } else /* If time-out is configured */ { /* Block task until the required flag are set or time-out occurred */ FlagBlock(&flagNode,flags,waitType); InsertDelayList(curTCB,timeout); OsSchedUnlock(); if(curTCB->pnode == Co_NULL) /* If time-out occurred */ { *perr = E_TIMEOUT; return 0; } else /* If the required flags are set */ { curTCB->pnode = Co_NULL; OsSchedLock(); springFlag = flags & FlagCrl.flagRdy; /* Clear the required ready flags or not */ pfcb->flagRdy &= ~(springFlag & pfcb->resetOpt); OsSchedUnlock(); *perr = E_OK; return springFlag; } } }