/** ******************************************************************************* * @brief Get a memory buffer from memory partition * @param[in] mmID Specify memory partition that want to assign buffer. * @param[out] None * @retval NULL Assign buffer fail. * @retval others Assign buffer successful,and return the buffer pointer. * * @par Description * @details This function is called to Delete a memory partition. ******************************************************************************* */ void* CoGetMemoryBuffer(OS_MMID mmID) { P_MM memCtl; P_MemBlk memBlk; #if CFG_PAR_CHECKOUT_EN >0 /* Check validity of parameter */ if(mmID >= CFG_MAX_MM) { return NULL; } if( ((1<<mmID)&MemoryIDVessel) == 0) { return NULL; } #endif memCtl = &MemoryTbl[mmID]; OsSchedLock(); /* Lock schedule */ if(memCtl->freeBlock == NULL ) /* Is there no free item in memory list */ { OsSchedUnlock(); /* Unlock schedule */ return NULL; /* Yes,error return */ } memBlk = (P_MemBlk)memCtl->freeBlock; /* Get free memory block */ memCtl->freeBlock = (U8*)memBlk->nextBlock; /* Reset the first free item */ OsSchedUnlock(); /* Unlock schedule */ return memBlk; /* Return free memory block address */ }
/** ******************************************************************************* * @brief Accept a semaphore without waitting * @param[in] id Event ID * @param[out] None * @retval E_INVALID_ID Invalid event ID. * @retval E_SEM_EMPTY No semaphore exist. * @retval E_OK Get semaphore successful. * * @par Description * @details This function is called accept a semaphore without waitting. ******************************************************************************* */ StatusType CoAcceptSem(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) { return E_INVALID_ID; } #endif 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 */ { OsSchedUnlock(); return E_SEM_EMPTY; } }
/** ******************************************************************************* * @brief Delete a flag * @param[in] id Flag ID. * @param[in] opt Delete option. * @param[out] None * @retval E_CALL Error call in ISR. * @retval E_INVALID_ID Invalid event ID. * @retval E_TASK_WAITTING Tasks waitting for the event,delete fail. * @retval E_OK Event deleted successful. * * @par Description * @details This function is called to delete a event flag. * @note ******************************************************************************* */ StatusType CoDelFlag(OS_FlagID id,U8 opt) { P_FLAG_NODE pnode; P_FCB pfcb; pfcb = &FlagCrl; if(OSIntNesting > 0) /* If be called from ISR */ { return E_CALL; } #if CFG_PAR_CHECKOUT_EN >0 if((pfcb->flagActive&(1<<id)) == 0) /* Flag is valid or not */ { return E_INVALID_ID; } #endif OsSchedLock(); pnode = pfcb->headNode; while(pnode != Co_NULL) /* Ready all tasks waiting for flags */ { if((pnode->waitFlags&(1<<id)) != 0) /* If no task is waiting on flags */ { if(opt == OPT_DEL_NO_PEND) /* Delete flag if no task waiting */ { OsSchedUnlock(); return E_TASK_WAITING; } else if (opt == OPT_DEL_ANYWAY) /* Always delete the flag */ { if(pnode->waitType == OPT_WAIT_ALL) { /* If the flag is only required by NODE */ if( pnode->waitFlags == (1<<id) ) { /* Remove the NODE from waiting list */ pnode = RemoveFromLink(pnode); continue; } else { pnode->waitFlags &= ~(1<<id); /* Update waitflags */ } } else { pnode = RemoveFromLink(pnode); continue; } } } pnode = pnode->nextNode; } /* Remove the flag from the flags list */ pfcb->flagActive &= ~(1<<id); pfcb->flagRdy &= ~(1<<id); pfcb->resetOpt &= ~(1<<id); OsSchedUnlock(); return E_OK; }
/** ******************************************************************************* * @brief Create a timer * @param[in] tmrType Specify timer's type. * @param[in] tmrCnt Specify timer initial counter value. * @param[in] tmrReload Specify timer reload value. * @param[in] func Specify timer callback function entry. * @param[out] None * @retval E_CREATE_FAIL Create timer fail. * @retval others Create timer successful. * * @par Description * @details This function is called to create a timer. ******************************************************************************* */ OS_TCID CoCreateTmr(U8 tmrType, U32 tmrCnt, U32 tmrReload, vFUNCPtr func) { U8 i; #if CFG_PAR_CHECKOUT_EN >0 /* Check validity of parameter */ if((tmrType != TMR_TYPE_ONE_SHOT) && (tmrType != TMR_TYPE_PERIODIC)) { return E_CREATE_FAIL; } if(func == NULL) { return E_CREATE_FAIL; } #endif OsSchedLock(); /* Lock schedule */ for(i = 0; i < CFG_MAX_TMR; i++) { if((TmrIDVessel & (1u << i)) == 0) /* Is free timer ID? */ { TmrIDVessel |= (1u<<i); /* Yes,assign ID to this timer */ OsSchedUnlock(); /* Unlock schedule */ TmrTbl[i].tmrID = i; /* Initialize timer as user set */ TmrTbl[i].tmrType = tmrType; TmrTbl[i].tmrState = TMR_STATE_STOPPED; TmrTbl[i].tmrCnt = tmrCnt; TmrTbl[i].tmrReload = tmrReload; TmrTbl[i].tmrCallBack = func; TmrTbl[i].tmrPrev = NULL; TmrTbl[i].tmrNext = NULL; return i; /* Return timer ID */ } } OsSchedUnlock(); /* Unlock schedule */ return E_CREATE_FAIL; /* Error return */ }
/** ******************************************************************************* * @brief Create a memory partition * @param[in] memBuf Specify memory partition head address. * @param[in] blockSize Specify memory block size. * @param[in] blockNum Specify memory block number. * @param[out] None * @retval E_CREATE_FAIL Create memory partition fail. * @retval others Create memory partition successful. * * @par Description * @details This function is called to create a memory partition. ******************************************************************************* */ OS_MMID CoCreateMemPartition(U8* memBuf,U32 blockSize,U32 blockNum) { U8 i,j; U8 *memory; P_MemBlk memBlk; memory = memBuf; #if CFG_PAR_CHECKOUT_EN >0 /* Check validity of parameter */ if(memBuf == NULL) { return E_CREATE_FAIL; } if(blockSize == 0) { return E_CREATE_FAIL; } if((blockSize&0x3) != 0) { return E_CREATE_FAIL; } if(blockNum<=1) { return E_CREATE_FAIL; } #endif OsSchedLock(); /* Lock schedule */ for(i = 0; i < CFG_MAX_MM; i++) { if((MemoryIDVessel & (1 << i)) == 0) /* Is free memory ID? */ { MemoryIDVessel |= (1<<i); /* Yes,assign ID to this memory block */ OsSchedUnlock(); /* Unlock schedule */ MemoryTbl[i].memAddr = memory;/* Initialize memory control block*/ MemoryTbl[i].freeBlock = memory; MemoryTbl[i].blockSize = blockSize; MemoryTbl[i].blockNum = blockNum; memBlk = (P_MemBlk)memory; /* Bulid list in this memory block*/ for(j=0;j<blockNum-1;j++) { memory = memory+blockSize; memBlk->nextBlock = (P_MemBlk)memory; memBlk = memBlk->nextBlock; } memBlk->nextBlock = NULL; return i; /* Return memory block ID */ } } OsSchedUnlock(); /* Unlock schedule */ return E_CREATE_FAIL; /* Error return */ }
/** ******************************************************************************* * @brief Post a mailbox * @param[in] id Event ID. * @param[in] pmail Pointer to mail that want to send. * @param[out] None * @retval E_INVALID_ID * @retval E_OK * * @par Description * @details This function is called to post a mail. * @note ******************************************************************************* */ StatusType CoPostMail(OS_EventID id,void* pmail) { P_ECB pecb; #if CFG_PAR_CHECKOUT_EN >0 if(id >= CFG_MAX_EVENT) { return E_INVALID_ID; /* Invalid id,return error */ } #endif pecb = &EventTbl[id]; #if CFG_PAR_CHECKOUT_EN >0 if(pecb->eventType != EVENT_TYPE_MBOX)/* Validate event control block type*/ { return E_INVALID_ID; /* Event is not mailbox,return error*/ } #endif if(pecb->eventCounter == 0) /* If mailbox doesn't already have a message*/ { OsSchedLock(); pecb->eventPtr = pmail; /* Place message in mailbox */ pecb->eventCounter = 1; EventTaskToRdy(pecb); /* Check waiting list */ OsSchedUnlock(); return E_OK; } else /* If there is already a message in mailbox */ { return E_MBOX_FULL; /* Mailbox is full,and return "E_MBOX_FULL" */ } }
/** ******************************************************************************* * @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 Start multitask * @param[in] None * @param[out] None * @retval None * * @par Description * @details This function is called to start multitask.After it is called, * OS start schedule task by priority or/and time slice. * @note This function must be called to start OS when you use CoOS,and must * call after CoOsInit(). ******************************************************************************* */ void CoStartOS(void) { TCBRunning = &TCBTbl[0]; /* Get running task */ TCBNext = TCBRunning; /* Set next scheduled task as running task */ TCBRunning->state = TASK_RUNNING; /* Set running task status to RUNNING */ RemoveFromTCBRdyList(TCBRunning); /* Remove running task from READY list */ OsSchedUnlock(); /* Enable Schedule,call task schedule */ }
/** ******************************************************************************* * @brief Assign a TCB to task being created * @param[in] None * @param[out] None * * @retval XXXX * * @par Description * @details This function is called to assign a task control block for task * being created. ******************************************************************************* */ static P_OSTCB AssignTCB(void) { P_OSTCB ptcb; OsSchedLock(); /* Lock schedule */ if(FreeTCB == Co_NULL) /* Is there no free TCB */ { OsSchedUnlock(); /* Yes,unlock schedule */ return Co_NULL; /* Error return */ } ptcb = FreeTCB; /* Yes,assgin free TCB for this task */ /* Set next item as the head of free TCB list */ FreeTCB = FreeTCB->TCBnext; OsSchedUnlock(); return ptcb; }
/** ******************************************************************************* * @brief AcceptSingleFlag * @param[in] id Flag ID. * @param[out] None * @retval E_INVALID_ID Invalid event ID. * @retval E_FLAG_NOT_READY Flag is not in ready state. * @retval E_OK The call was successful and your task owns the Flag. * * @par Description * @details This fucntion is called to accept single flag * @note ******************************************************************************* */ StatusType CoAcceptSingleFlag(OS_FlagID id) { P_FCB pfcb; pfcb = &FlagCrl; #if CFG_PAR_CHECKOUT_EN >0 if(id >= FLAG_MAX_NUM) { return E_INVALID_ID; /* Invalid 'id',return error */ } if((pfcb->flagActive&(1<<id)) == 0) { return E_INVALID_ID; /* Flag is deactive,return error */ } #endif if((pfcb->flagRdy&(1<<id)) != 0) /* If the required flag is set */ { OsSchedLock() pfcb->flagRdy &= ~((FlagCrl.resetOpt)&(1<<id)); /* Clear the flag */ OsSchedUnlock(); return E_OK; } else /* If the required flag is not set */ { return E_FLAG_NOT_READY; } }
/** ******************************************************************************* * @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(); pecb->eventCounter++; /* Increment semaphore count to register event */ EventTaskToRdy(pecb); /* Check semaphore event waiting list */ OsSchedUnlock(); return E_OK; }
/** ******************************************************************************* * @brief System tick interrupt handler. * @param[in] None * @param[out] None * @retval None * * @par Description * @details This is system tick interrupt headler. * @note CoOS may schedule when exiting this ISR. ******************************************************************************* */ void SysTick_Handler(void) { OSSchedLock++; /* Lock scheduler. */ OSTickCnt++; /* Increment systerm time. */ #if CFG_TASK_WAITTING_EN >0 if(DlyList != Co_NULL) { /* Have task in delay list? */ if(DlyList->delayTick > 1) { /* Delay time > 1? */ DlyList->delayTick--; /* Decrease delay time of the list head. */ } else { DlyList->delayTick = 0; isr_TimeDispose(); /* Call hander for delay time list */ } } #endif #if CFG_TMR_EN > 0 if(TmrList != Co_NULL) { /* Have timer in working? */ if(TmrList->tmrCnt > 1) { /* Timer time > 1? */ TmrList->tmrCnt--; /* Decrease timer time of the list head. */ } else { TmrList->tmrCnt = 0; isr_TmrDispose(); /* Call hander for timer list */ } } #endif TaskSchedReq = Co_TRUE; OsSchedUnlock(); }
/** ******************************************************************************* * @brief Get free block number in a memory partition * @param[in] mmID Specify memory partition. * * @param[out] E_INVALID_ID Invalid ID was passed and get counter failure. * @param[out] E_OK Get current counter successful. * @retval fbNum The number of free block. * * @par Description * @details This function is called to get free block number in a memory * partition. ******************************************************************************* */ U32 CoGetFreeBlockNum(OS_MMID mmID,StatusType* perr) { U32 fbNum; P_MM memCtl; P_MemBlk memBlk; #if CFG_PAR_CHECKOUT_EN >0 /* Check validity of parameter */ if(mmID >= CFG_MAX_MM) { *perr = E_INVALID_ID; return 0; } if( ((1<<mmID)&MemoryIDVessel) == 0) { *perr = E_INVALID_ID; /* Invalid memory id,return 0 */ return 0; } #endif memCtl = &MemoryTbl[mmID]; OsSchedLock(); /* Lock schedule */ memBlk = (P_MemBlk)(memCtl->freeBlock);/* Get the free item in memory list*/ fbNum = 0; while(memBlk != NULL) /* Get counter of free item */ { fbNum++; memBlk = memBlk->nextBlock; /* Get next free iterm */ } OsSchedUnlock(); /* Unlock schedul */ *perr = E_OK; return fbNum; /* Return the counter of free item */ }
/** ******************************************************************************* * @brief Set a flag * @param[in] id Flag ID. * @param[out] None * @retval E_INVALID_ID Invalid event ID. * @retval E_OK Event deleted successful. * * @par Description * @details This function is called to set a flag. * @note ******************************************************************************* */ StatusType CoSetFlag(OS_FlagID id) { P_FLAG_NODE pnode; P_FCB pfcb; pfcb = &FlagCrl; #if CFG_PAR_CHECKOUT_EN >0 if(id >= FLAG_MAX_NUM) /* Flag is valid or not */ { return E_INVALID_ID; /* Invalid flag id */ } if((pfcb->flagActive&(1<<id)) == 0) { return E_INVALID_ID; /* Flag is not exist */ } #endif if((pfcb->flagRdy&(1<<id)) != 0) /* Flag had already been set */ { return E_OK; } pfcb->flagRdy |= (1<<id); /* Update the flags ready list */ OsSchedLock(); pnode = pfcb->headNode; while(pnode != Co_NULL) { if(pnode->waitType == OPT_WAIT_ALL) /* Extract all the bits we want */ { if((pnode->waitFlags&pfcb->flagRdy) == pnode->waitFlags) { /* Remove the flag node from the wait list */ pnode = RemoveFromLink(pnode); if((pfcb->resetOpt&(1<<id)) != 0)/* If the flags is auto-reset*/ { break; } continue; } } else /* Extract only the bits we want */ { if( (pnode->waitFlags & pfcb->flagRdy) != 0) { /* Remove the flag node from the wait list */ pnode = RemoveFromLink(pnode); if((pfcb->resetOpt&(1<<id)) != 0) { break; /* The flags is auto-reset */ } continue; } } pnode = pnode->nextNode; } OsSchedUnlock(); return E_OK; }
/** ******************************************************************************* * @brief Release a ECB * @param[in] pecb A pointer to event control block which be released. * @param[out] None * @retval None * * @par Description * @details This function is called to release a event control block when a * event be deleted. ******************************************************************************* */ static void ReleaseECB(P_ECB pecb) { pecb->eventType = EVENT_TYPE_INVALID; /* Sign that not to use. */ OsSchedLock(); /* Lock schedule */ pecb->eventPtr = FreeEventList; /* Release ECB that event hold */ FreeEventList = pecb; /* Reset free event item */ OsSchedUnlock(); /* Unlock schedule */ }
/** ******************************************************************************* * @brief Accept a mail from queue * @param[in] id Event ID. * @param[out] perr A pointer to error code. * @retval NULL * @retval A pointer to mail accepted. * * @par Description * @details This function is called to accept a mail from queue. * @note ******************************************************************************* */ void* CoAcceptQueueMail(OS_EventID id,StatusType* perr) { P_ECB pecb; P_QCB pqcb; void* pmail; #if CFG_PAR_CHECKOUT_EN >0 if(id >= CFG_MAX_EVENT) { *perr = E_INVALID_ID; /* Invalid id,return error */ return NULL; } #endif pecb = &EventTbl[id]; #if CFG_PAR_CHECKOUT_EN >0 if(pecb->eventType != EVENT_TYPE_QUEUE)/* Invalid event control block type*/ { *perr = E_INVALID_ID; return NULL; } #endif pqcb = (P_QCB)pecb->eventPtr; /* Point at queue control block */ OsSchedLock(); 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) { pqcb->head = 0; } OsSchedUnlock(); *perr = E_OK; return pmail; /* Return message received */ } else /* If there is no message in the queue*/ { OsSchedUnlock(); *perr = E_QUEUE_EMPTY; return NULL; /* Return NULL */ } }
/** ******************************************************************************* * @brief Create a queue * @param[in] qStart Pointer to mail pointer buffer. * @param[in] size The length of queue. * @param[in] sortType Mail queue waiting list sort type. * @param[out] None * @retval E_CREATE_FAIL Create queue fail. * @retval others Create queue successful. * * @par Description * @details This function is called to create a queue. * @note ******************************************************************************* */ OS_EventID CoCreateQueue(void **qStart, U16 size ,U8 sortType) { U8 i; P_ECB pecb; #if CFG_PAR_CHECKOUT_EN >0 if((qStart == NULL) || (size == 0)) { return E_CREATE_FAIL; } #endif OsSchedLock(); for(i = 0; i < CFG_MAX_QUEUE; i++) { /* Assign a free QUEUE control block */ if((QueueIDVessel & (1u << i)) == 0) { QueueIDVessel |= (1u<<i); OsSchedUnlock(); QueueTbl[i].qStart = qStart; /* Initialize the queue */ QueueTbl[i].id = i; QueueTbl[i].head = 0; QueueTbl[i].tail = 0; QueueTbl[i].qMaxSize = size; QueueTbl[i].qSize = 0; /* Get a event control block and initial the event content */ pecb = CreatEvent(EVENT_TYPE_QUEUE,sortType,&QueueTbl[i]); if(pecb == NULL ) /* If there is no free EVENT control block*/ { return E_CREATE_FAIL; } return (pecb->id); } } OsSchedUnlock(); return E_CREATE_FAIL; /* There is no free QUEUE control block */ }
/** ******************************************************************************* * @brief Create a event * @param[in] eventType The type of event which being created. * @param[in] eventSortType Event sort type. * @param[in] eventCounter Event counter,ONLY for EVENT_TYPE_SEM. * @param[in] eventPtr Event struct pointer,ONLY for Queue.NULL for other * event type. * @param[out] None * @retval NULL Invalid pointer,create event fail. * @retval others Pointer to event control block which had assigned right now. * * @par Description * @details This function is called by CreateSem(),... * to get a event control block and initial the event content. * * @note This is a internal function of CooCox CoOS,User can't call. ******************************************************************************* */ P_ECB CreatEvent(U8 eventType,U8 eventSortType,void* eventPtr) { P_ECB pecb; OsSchedLock(); /* Lock schedule */ if(FreeEventList == NULL) /* Is there no free evnet item */ { OsSchedUnlock(); /* Yes,unlock schedule */ return NULL; /* Return error */ } pecb = FreeEventList;/* Assign the free event item to this event */ FreeEventList = FreeEventList->eventPtr; /* Reset free event item */ OsSchedUnlock(); /* Unlock schedul */ pecb->eventType = eventType; /* Initialize event item as user set */ pecb->eventSortType = eventSortType; pecb->eventPtr = eventPtr; pecb->eventTCBList = NULL; return pecb; /* Return event item pointer */ }
/** ******************************************************************************* * @brief Create a flag * @param[in] bAutoReset Reset mode,Co_TRUE(Auto Reset) FLASE(Manual Reset). * @param[in] bInitialState Initial state. * @param[out] None * @retval E_CREATE_FAIL Create flag fail. * @retval others Create flag successful. * * @par Description * @details This function use to create a event flag. * @note ******************************************************************************* */ OS_FlagID CoCreateFlag(BOOL bAutoReset,BOOL bInitialState) { U8 i; OsSchedLock(); for(i=0;i<FLAG_MAX_NUM;i++) { /* Assign a free flag control block */ if((FlagCrl.flagActive&(1<<i)) == 0 ) { FlagCrl.flagActive |= (1<<i); /* Initialize active flag */ FlagCrl.flagRdy |= (bInitialState<<i);/* Initialize ready flag */ FlagCrl.resetOpt |= (bAutoReset<<i);/* Initialize reset option */ OsSchedUnlock(); return i ; /* Return Flag ID */ } } OsSchedUnlock(); return E_CREATE_FAIL; /* There is no free flag control block*/ }
/** ******************************************************************************* * @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 AcceptMultipleFlags * @param[in] flags Flags that waiting to active task. * @param[in] waitType Flags wait type. * @param[out] perr A pointer to error code. * @retval 0 * @retval springFlag * * @par Description * @details This fucntion is called to accept multiple flags. * @note ******************************************************************************* */ U32 CoAcceptMultipleFlags(U32 flags,U8 waitType,StatusType *perr) { U32 springFlag; P_FCB pfcb; pfcb = &FlagCrl; #if CFG_PAR_CHECKOUT_EN >0 if((flags&pfcb->flagActive) != flags ) /* Judge flag is active or not? */ { *perr = E_INVALID_PARAMETER; /* Invalid flags */ return 0; } #endif springFlag = flags & pfcb->flagRdy; OsSchedLock(); /* If any required flags are set */ if( (springFlag != 0) && (waitType == OPT_WAIT_ANY) ) { pfcb->flagRdy &= ~(springFlag & pfcb->resetOpt); /* Clear the flags */ 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; } OsSchedUnlock(); *perr = E_FLAG_NOT_READY; return 0; }
/** ******************************************************************************* * @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 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 Free a memory buffer to memory partition * @param[in] mmID Specify memory partition. * @param[in] buf Specify memory buffer that want to free. * @param[out] None * @retval E_INVALID_ID The memory partition id passed was invalid. * @retval E_INVALID_PARAMETER The parameter passed was invalid. * @retval E_OK Free successful. * * @par Description * @details This function is called to Delete a memory partition. ******************************************************************************* */ StatusType CoFreeMemoryBuffer(OS_MMID mmID,void* buf) { P_MM memCtl; P_MemBlk memBlk; #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; } if(buf == NULL) { return E_INVALID_PARAMETER; } #endif memCtl = &MemoryTbl[mmID]; #if CFG_PAR_CHECKOUT_EN >0 /* Check validity of parameter */ if((U32)buf < (U32)(memCtl->memAddr)) { return E_INVALID_PARAMETER; } if((U32)buf > (U32)(memCtl->memAddr + memCtl->blockSize*memCtl->blockNum)) { return E_INVALID_PARAMETER; } if(((U32)buf - (U32)(memCtl->memAddr))%(memCtl->blockSize) != 0) { return E_INVALID_PARAMETER; } #endif memBlk = (P_MemBlk)buf; /* Reset the first free item */ OsSchedLock(); memBlk->nextBlock = (P_MemBlk)memCtl->freeBlock; memCtl->freeBlock = buf; OsSchedUnlock(); 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 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 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 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 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 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; }