00001 /* 00002 * Femto OS v 0.91 - Copyright (C) 2008-2009 Ruud Vlaming 00003 * 00004 * This file is part of the Femto OS distribution. 00005 * 00006 * This program is free software: you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation, version 3 of the License. 00009 * 00010 * This program is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 * GNU General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU General Public License 00016 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00017 * 00018 * Please note that, due to the GPLv3 license, for application of this 00019 * work and/or combined work in embedded systems special obligations apply. 00020 * If these are not to you liking, please know the Femto OS is dual 00021 * licensed. A commercial license and support are available. 00022 * See http://www.femtoos.org/ for details. 00023 */ 00024 00025 #include "femtoos_core.h" 00026 #include "femtoos_shared.h" 00027 00028 00029 /* ========================================================================= */ 00030 /* FEMTO OS INTERNAL FUNCTIONS ============================================ */ 00031 /* ========================================================================= */ 00032 00033 /* 00034 * Body definitions. All switching methods are called via an assembler 00035 * redirect, making it possible to switch stack, save context and preserve 00036 * all registers (including the parameters) while doing so. Without this 00037 * trick gcc may push the parameter registers or construct a frame pointer 00038 * first thereby destroying other registers. Notice functions never return, 00039 * but are not 'noreturn'. They are naked or bikini. 00040 */ 00041 00049 #if (includeTaskDelayFromNow == cfgTrue) 00050 static void privDelayFromNowBody(Tuint16 uiTicksToWait) __attribute__((used)) defSysReduceProEpilogue; 00051 #endif 00052 00062 #if (includeTaskDelayFromWake == cfgTrue) 00063 static void privDelayFromWakeBody(Tuint16 uiTicksToWait) __attribute__((used)) defSysReduceProEpilogue; 00064 #endif 00065 00071 #if (includeTaskRecreate == cfgTrue) 00072 static void privRecreateBody(Tuint08 uiTaskNumber) __attribute__((used)) defSysReduceProEpilogue; 00073 #endif 00074 00080 #if (includeTaskRestart == cfgTrue) 00081 static void privRestartBody(Tuint08 uiRestartMode, Tuint16 uiTicksToWait) __attribute__((used)) defSysReduceProEpilogue; 00082 #endif 00083 00089 #if (includeTaskYield == cfgTrue) 00090 static void privYieldBody(void) __attribute__((used)) defSysReduceProEpilogue; 00091 #endif 00092 00098 #if (includeTaskTerminate == cfgTrue) 00099 static void privTerminateBody(Tuint08 uiTaskNumber) __attribute__((used)) defSysReduceProEpilogue; 00100 #endif 00101 00107 #if (includeTaskSuspend == cfgTrue) 00108 static void privSuspendBody(Tuint08 uiSuspendMode) __attribute__((used)) defSysReduceProEpilogue; 00109 #endif 00110 00116 #if (cfgUseLowPowerSleep == cfgTrue) && (includeTaskSleep == cfgTrue) 00117 static void privSleepBody(void) __attribute__((used)) defSysReduceProEpilogue; 00118 #endif 00119 00125 #if (cfgUseLowPowerSleep == cfgTrue) && (includeTaskSleepAll == cfgTrue) 00126 static void privSleepAllBody(void) __attribute__((used)) defSysReduceProEpilogue; 00127 #endif 00128 00134 #if (cfgUseSynchronization != cfgSyncNon) && (includeTaskWaitForTasks == cfgTrue) 00135 #if (cfgUseTimeout == cfgTrue) 00136 static void privWaitForTasksBody(Tuint08 uiSlot, Tuint08 uiNumberOfTasks, Tuint16 uiTicksToWait) __attribute__((used)) defSysReduceProEpilogue; 00137 #else 00138 static void privWaitForTasksBody(Tuint08 uiSlot, Tuint08 uiNumberOfTasks) __attribute__((used)) defSysReduceProEpilogue; 00139 #endif 00140 #endif 00141 00147 #if (cfgUseSynchronization != cfgSyncNon) && ( (includeTaskQueu == cfgTrue) || (includeTaskMutex == cfgTrue) ) 00148 #if (cfgUseTimeout == cfgTrue) 00149 #if (cfgUseSynchronization == cfgSyncDoubleBlock) 00150 static void privSyncRequestBody(Tuint08 uiSlotSlot, Tsint08 siFreeLeftFilling, Tsint08 siFreeRightFilling, Tuint16 uiTicksToWait) __attribute__((used)) defSysReduceProEpilogue; 00151 #else 00152 static void privSyncRequestBody(Tuint08 uiSlotSlot, Tsint08 siFreeRightFilling, Tuint16 uiTicksToWait) __attribute__((used)) defSysReduceProEpilogue; 00153 #endif 00154 #else 00155 #if (cfgUseSynchronization == cfgSyncDoubleBlock) 00156 static void privSyncRequestBody(Tuint08 uiSlotSlot, Tsint08 siFreeLeftFilling, Tsint08 siFreeRightFilling) __attribute__((used)) defSysReduceProEpilogue; 00157 #else 00158 static void privSyncRequestBody(Tuint08 uiSlotSlot, Tsint08 siFreeRightFilling) __attribute__((used)) defSysReduceProEpilogue; 00159 #endif 00160 #endif 00161 #endif 00162 00168 #if (cfgUseSynchronization != cfgSyncNon) && ( (includeTaskQueu == cfgTrue) || (includeTaskMutex == cfgTrue) ) 00169 static void privSyncReleaseBody(Tuint08 uiSlotSlot) __attribute__((used)) defSysReduceProEpilogue; 00170 #endif 00171 00177 #if (cfgUseFileSystem == cfgTrue) && (includeTaskFileAccess == cfgTrue) 00178 #if (cfgUseTimeout == cfgTrue) 00179 #if (cfgUseFileSystemConcurrentRead == cfgTrue) 00180 static void privFileOpenBody(Tbool bReadOnly, Tuint16 uiTicksToWait) __attribute__((used)) defSysReduceProEpilogue; 00181 #else 00182 static void privFileOpenBody(Tuint16 uiTicksToWait) __attribute__((used)) defSysReduceProEpilogue; 00183 #endif 00184 #else 00185 #if (cfgUseFileSystemConcurrentRead == cfgTrue) 00186 static void privFileOpenBody(Tbool bReadOnly) __attribute__((used)) defSysReduceProEpilogue; 00187 #else 00188 static void privFileOpenBody(void) __attribute__((used)) defSysReduceProEpilogue; 00189 #endif 00190 #endif 00191 #endif 00192 00198 #if (cfgUseFileSystem == cfgTrue) && (includeTaskFileAccess == cfgTrue) 00199 static void privFileCloseBody(void) __attribute__((used)) defSysReduceProEpilogue; 00200 #endif 00201 00207 #if (cfgUseFileSystem == cfgTrue) 00208 static void privWaitForFsAccessBody(void) __attribute__((used)) defSysReduceProEpilogue; 00209 #endif 00210 00216 #if (cfgUseEvents == cfgTrue) && (includeTaskWaitForEvents == cfgTrue) 00217 #if (cfgUseTimeout == cfgTrue) 00218 static void privWaitForEventBody(Tuint08 uiEvent, Tuint16 uiTicksToWait) __attribute__((used)) defSysReduceProEpilogue; 00219 #else 00220 static void privWaitForEventBody(Tuint08 uiEvent) __attribute__((used)) defSysReduceProEpilogue; 00221 #endif 00222 #endif 00223 00231 #if (defCheckReportingError == cfgTrue) 00232 #if (cfgCheckAlwaysFatal == cfgTrue) 00233 static void privShowError(Tuint08 uiMessage, Tuint08 uiCallId, Tuint08 uiInfo) __attribute__ (( noreturn )); 00234 #else 00235 static void privShowError(Tuint08 uiMessage, Tuint08 uiCallId, Tuint08 uiInfo); 00236 #endif 00237 #endif 00238 00245 #if (cfgCheckOsStack == cfgTrue) || (cfgCheckWatermarks == cfgTrue) 00246 static void privCheckOsStackLevel(void); 00247 #endif 00248 00255 #if (cfgCheckWatermarks == cfgTrue) && (cfgSysReuseOsStack == cfgFalse) 00256 static void privCheckOsStackRegion(void); 00257 #endif 00258 00264 #ifdef portInitContext 00265 static Taddress privInitContext(Taddress pTaskStart, Taddress pStackTop, Tuint08 uiRegisterCount, Tuint08 uiInterruptStart); 00266 #endif 00267 00276 static TtaskControlBlock * privTcbList(Tuint08 uiTaskNumber) __attribute__ ((pure, noinline)); 00277 00284 static Tuint08 privTaskNumber(Tuint08 uiTaskNumber) __attribute__ ((pure, noinline, unused)); 00285 00293 #if (cfgCheckTaskStack == cfgTrue) && (StackSafety > 0) 00294 static void privTestStackRegion(void) __attribute__ (( noinline)); 00295 #endif 00296 00305 #if (cfgUseLowPowerSleep == cfgTrue) 00306 static void privWakeupFromLowPower(void) __attribute__ ((noinline)); 00307 #endif 00308 00319 #if (defRegisterUseConstant == cfgFalse) 00320 static Tuint08 privRegisterCount(Tuint08 uiRegisterUse) __attribute__ ((const)); 00321 #endif 00322 00323 /*DISCUSSION 00324 * Some methods use quite a bit of stack, i.e. they start by saving 00325 * say 10 registers on the context. This implies not only 10 more bytes 00326 * of ram use, but also 40 extra flash bytes just to store and retrieve 00327 * the bytes. This must be weighed against inlining those methods. 00328 * Less stack, more flash, but maybe not that much more. It really depends 00329 * which resource is limited. 00330 * Also that discussion cannot be made per function, since you cannot simply 00331 * add the stack use. Functions could be inlined if needed by adding 00332 * __attribute__ ( ( always_inline ) ); 00333 * to their definitions. 00334 */ 00335 00344 static void privTaskInit(Tuint08 uiTaskNumber, Tuint08 uiInitControl); 00345 00354 static void privEnterOS(Tuint08 uiAction) defSysReduceProEpilogue; 00355 00363 static void privIncrementTick(void); 00364 00371 static Tuint08 privSwitchContext(void); 00372 00380 static Tselect privSelectTask(Tuint08 uiFlipMask, Tuint08 uiLoopStart, Tuint08 uiLoopEnd) __attribute__ (( always_inline )); 00381 00388 #if (cfgUseHierarchicalRoundRobin == cfgTrue) 00389 static void privMakeTasksRunable(Tuint08 uiFlipMask, Tuint08 uiPriority, Tuint08 uiLoopStart, Tuint08 uiLoopEnd, Tbool bCheckSkip) __attribute__ (( always_inline )); 00390 #else 00391 static void privMakeTasksRunable(Tuint08 uiFlipMask, Tuint08 uiLoopStart, Tuint08 uiLoopEnd, Tbool bCheckSkip) __attribute__ (( always_inline )); 00392 #endif 00393 00401 #if (cfgUseLowPowerSleep == cfgTrue) 00402 static void privEnterSleep(Tuint08 uiTickMinDelay); 00403 #endif 00404 00412 static void privEnterIdle(void) defSysReduceProEpilogue; 00413 00421 static void privEnterTask(void) defSysReduceProEpilogue; 00422 00429 #if (cfgUseLoadMonitor == cfgTrue) 00430 static void privCopyLoad(void); 00431 #endif 00432 00439 #if (cfgCheckWatermarks == cfgTrue) && (cfgCheckTrace == cfgTrue) 00440 static void privTraceWatermarks(void); 00441 #endif 00442 00449 #if (defUseDelay == cfgTrue) 00450 static void privWakeupFromDelay(Tuint08 uiTaskNumber, TtaskControlBlock * taskTCB); 00451 #endif 00452 00459 #if (defUseDelay == cfgTrue) 00460 #if (includeTaskDelayFromWake == cfgTrue) 00461 #define privDelayCalcFromNow(DT) privDelayCalc(DT,true) 00462 #define privDelayCalcFromWake(DT) privDelayCalc(DT,false) 00463 static void privDelayCalc(Tuint16 uiDelayTime, Tbool bFromNow) defConditionalInline; 00464 #else 00465 static void privDelayCalcFromNow(Tuint16 delayTime) defConditionalInline; 00466 #endif 00467 #endif 00468 00474 #if (cfgUseSynchronization != cfgSyncNon) && ((cfgUseTaskWatchdog == cfgTrue) || ( includeTaskRecreate == cfgTrue )) 00475 static void privCleanSlotStack(TtaskExtendedControlBlock * taskTCB); 00476 #endif 00477 00484 #if (cfgUseSynchronization != cfgSyncNon) 00485 static Tbool privOperateSlotStack(Tuint08 uiControlTaskNumber, Tuint08 uiSlotSlot); 00486 #endif 00487 00493 #if (cfgUseSynchronization != cfgSyncNon) && (defUseQueus == cfgTrue) 00494 static Tuint08 privGetQueuSize(Tuint08 uiQueuNumber) __attribute__ ((always_inline, const)); 00495 #endif 00496 00497 00507 #if (cfgUseSynchronization != cfgSyncNon) || (cfgUseFileSystem == cfgTrue) 00508 static void privUnblockTask(Tuint08 uiControlTaskNumber); 00509 #endif 00510 00518 #if (cfgUseSynchronization != cfgSyncNon) && (cfgUsePriorityLifting == cfgTrue) 00519 static void privLiftLocksOnSlot(Tuint08 uiSlot); 00520 #endif 00521 00529 #if (cfgUseSynchronization != cfgSyncNon) && (cfgUsePriorityLifting == cfgTrue) 00530 static void privRestoreInitialPriority(Tuint08 uiTaskNumber); 00531 #endif 00532 00540 #if (cfgUseSynchronization != cfgSyncNon) && (defUseQueus == cfgTrue) 00541 static Tuint08 privQueuTest(Tuint08 uiSlot, Tsint08 siFreeFilling); 00542 #endif 00543 00552 #if (cfgUseSynchronization != cfgSyncNon) && ((defUseMutexes == cfgTrue) || (defUseQueus == cfgTrue)) 00553 static void privReleaseSyncBlockingTasks(void) defConditionalInline; 00554 #endif 00555 00564 #if (cfgUseSynchronization != cfgSyncNon) && ((defUseMutexes == cfgTrue) || (defUseQueus == cfgTrue)) 00565 static Tuint08 privFreeLockAbsent(Tuint08 uiSlot); 00566 #endif 00567 00576 #if (cfgUseSynchronization != cfgSyncNon) && (defUseQueus == cfgTrue) 00577 static Tbool privSizeFitsQueu(Tuint08 uiSlot, Tsint08 siFreeFilling); 00578 #endif 00579 00587 #if (cfgUseFileSystem == cfgTrue) 00588 static void privReleaseFileBlocks(void); 00589 #endif 00590 00598 #if (cfgUseFileSystem == cfgTrue) 00599 static Taddress privFileLocation(Tuint08 uiFileNumber, Tuint08 uiOffset); 00600 #endif 00601 00608 #if (cfgUseLowPowerSleep == cfgTrue) && (includeTaskSleepAll == cfgTrue) 00609 static void privPutAllTasksToSleep(void); 00610 #endif 00611 00620 #if (cfgUseFileSystem == cfgTrue) 00621 static void privPrepareFileClose(Tuint08 uiTaskNumber); 00622 #endif 00623 00632 #if (cfgUseFileSystem == cfgTrue) && (cfgCheckMethodUse == cfgTrue) 00633 static void privCheckFileSpecsWriting(Tuint08 uiFileNumber, Tuint08 uiOffset, Tuint08 uiSize, Tuint08 uiCallId); 00634 #endif 00635 00644 #if (cfgUseFileSystem == cfgTrue) && (cfgCheckMethodUse == cfgTrue) 00645 static void privCheckFileSpecsReading(Tuint08 uiFileNumber, Tuint08 uiOffset, Tuint08 uiSize, Tuint08 uiCallId); 00646 #endif 00647 00654 #if (cfgUseFileSystem == cfgTrue) && ( ((cfgUseFileSystemMaintainFAT == cfgTrue) && (includeTaskFileAppendByte == cfgTrue)) || (cfgCheckMethodUse == cfgTrue) ) 00655 static Tuint08 privFileSpace(Tuint08 uiFileNumber); 00656 #endif 00657 00664 #if (cfgCheckMethodUse == cfgTrue) 00665 #if (defCapabilitiesFull == cfgFalse) 00666 static void privCheckCapabilities(Tuint08 uiCallId, Tuint08 uiTaskCaps) __attribute__ ((unused)); 00667 #else 00668 #define privCheckCapabilities(X,Y) 00669 #endif 00670 #endif 00671 00672 00673 /* ========================================================================= */ 00674 /* FEMTO OS CORE IMPLEMENTATION ============================================ */ 00675 /* ========================================================================= */ 00676 00677 00678 #if (defCheckReportingError == cfgTrue) 00679 00680 static void privShowError(Tuint08 uiMessage, Tuint08 uiCallId, Tuint08 uiInfo) 00681 { /* We may arrive here from OS space, isr or task space. In the latter case is important we do 00682 * not get tick interrupts (only possible when coming from a task), since reporting an error 00683 * is usually a critical situation. But since we want the user to see the error it is best 00684 * we stop all interrupts. 00685 * Note that for tasks this method should not return to the point of calling but invoke a 00686 * context switch instead. When coming from an isr, we cannot stop that particular isr so 00687 * we should treat that situation as fatal. Only when coming here from the OS itself, we 00688 * may return if that was specifically asked for, or we must switch to a new task (usually 00689 * can a switching method was called from the task). Only when the possibility exists we 00690 * return to the point of origin we need to keep the stack. 00691 * The only question remains, how do we decide where the error occurred. On course we 00692 * can ask the uiOsStatus. If we come from genXXX that is the only way to find out. But, 00693 * if we come for example from privInitOS, this information has not yet been updated, 00694 * or if we come from a switching call, we are not really inside OS space, but we are 00695 * handling a call from the task in OS space. Therefore we have one bit controlling 00696 * if we should use the uiOsState "as-is" or if we should use the Os State forced. 00697 * 00698 * Then, with the resulting state being (idle, isr, task, os) 00699 * idle => issue an internal error, this should not happen. TODO: not implemented yet. 00700 * isr => make error fatal, renew stack, never return 00701 * => we should not arrive here from a sleeping state. 00702 * task => if fatal error, renew stack, never return 00703 * => if non-fatal error, renew stack, terminate task, issue a switch-task 00704 * => for shared tasks, reset the share state 00705 * os => if fatal error, renew stack, never return 00706 * => if non-fatal error return to place from which the call originated. 00707 * Of course, when cfgCheckAlwaysFatal is activated the error is ... always fatal, 00708 * so we can ignore this hocus-pocus. 00709 * A switch task is a context switch without the without the context-save and os 00710 * initialization operations. 00711 * 00712 * One extra note. Errors reporting an incorrect task number must be fatal since this 00713 * routine assumes that, when the error is not fatal, the task number represents the 00714 * failing task. 00715 */ 00716 privDisableGlobalInterrupts(); 00717 /* Strip the error type information from the message */ 00718 Tuint08 uiBareMessage = (uiMessage & errMessageGetMask); 00719 /* Errors are traced first, to be sure that tracing is done in case the portError holds the system for ever. */ 00720 privTrace(traceErrorBase | uiBareMessage); 00721 /* First check if we have fatal errors per default */ 00722 #if (cfgCheckAlwaysFatal == cfgTrue) 00723 /* If so, the matter is simple. All errors are fatal and we never return. */ 00724 const Tbool bFatal = true; 00725 const Tbool bReturn = false; 00726 #else 00727 /* uiWorkStatus represents the status we will use upon which we decide what to do. */ 00728 Tuint08 uiWorkStatus; 00729 /* See if we must use the uiOsStatus as a basis (standard) or the given by the uiCallId. */ 00730 if ((uiMessage & errOsStateGetMask) == errOsStateAsIs) 00731 { /* Extract the upper two bits containing the status info from the standard status. */ 00732 uiWorkStatus = uiOsStatus & defContextGetMask; } 00733 else 00734 { /* Use the StateOs as forced status (i.e. assume we are in the OS state) */ 00735 uiWorkStatus = defContextStateOs; } 00736 /* We first calculate when we have a fatal error. That is the case is the error in itself is 00737 * fatal, or if we arrive here from an isr. */ 00738 const Tbool bFatal = (uiBareMessage >= errFatalError) || (uiWorkStatus == defContextStateIsr); 00739 /* We may normally return only in one special case. Of course the error may not be fatal, and we must come 00740 * here from the OS itself, (or we must be told we come from the OS itself) */ 00741 const Tbool bReturn = !bFatal && (uiWorkStatus == defContextStateOs); 00742 #endif 00743 /* Strip the error type information from the call Id */ 00744 Tuint08 uiBareCallId = (uiCallId & errCallIdGetMask); 00745 /* If we do not return we reset the stack to prevent stack overflow when handling the error code. 00746 * We don't need the preserve stack anymore. Note, that we should note have a stack frame present. 00747 * Pushed variables are not important when we no not return. */ 00748 if (!bReturn) { privSetStack(&xOS.StackOS[OSstackInit]); } 00749 /* We disable tick interrupts, needed to be deactivated in case we should return. We do that here, after a possible 00750 * stack transplant since this call may make use of the stack. It must be done before global interrupts are 00751 * activated again. */ 00752 privDisableTickInterrupts(); 00753 /* Now determine the task number. */ 00754 Tuint08 uiTaskNumber; 00755 /* Test if we must use the given task number by uiInfo or the current one. This flag is used because 00756 * from a lot of places its much sorter to set the flag than to calculate the current task number. 00757 * Do not use the privTaskNumber() method, for we do not want to introduce stack use here. */ 00758 if ((uiMessage & errTaskStateGetMask) == errTaskStateCurrent) 00759 { /* Deduce the current task number from the Status */ 00760 uiTaskNumber = (uiOsStatus & defTaskNumberGetMask) >> defOsTaskNumberShift; 00761 /* Reconstruct the uiInfo byte, that will be send to the error method later on */ 00762 uiInfo = (uiInfo & errTaskNumberSetMask) | (uiTaskNumber << errTaskNumberShift); } 00763 else 00764 { /* Read the task number from the given byte, probably the current task is not the one giving problems */ 00765 uiTaskNumber = (uiInfo & errTaskNumberGetMask) >> errTaskNumberShift ; } 00766 /* Now, show the error, if we had a fatal error it makes no sense to continue operations, 00767 * so the only thing we can do is show the error again*/ 00768 do { portShowError(uiBareMessage,uiBareCallId,uiInfo); } while (bFatal); 00769 /* Now, if we return, we must be sure we have enough OS stack space. Since error handling can be 00770 * stack hungry, let us check that here. This may invoke an other error. But since we know 00771 * that, if it occurs, it will be fatal, there cannot be a loop. */ 00772 #if (cfgCheckOsStack == cfgTrue) 00773 privCheckOsStackLevel(); 00774 #endif 00775 /* In case we had a normal error we want to continue, but since it is reasonable to assume that it 00776 * may have taken some time, the user has probably stop the timer, if he did not misused the timer 00777 * to make some leds blink. In any case its best to restart the timer. We have to live with the 00778 * fact that real time and timer ticks are out of sync anyway. Note that the user may use the timer, 00779 * but may not activate the interrupt. */ 00780 portSetupTimerInterrupt(); 00781 /* We return from this call with a setup timer, and with tick interrupts disabled. The global interrupts 00782 * are still disabled. If we have no os protection we must re-enable global interrupts again. */ 00783 #if (cfgIntOsProtected == cfgFalse) 00784 privEnableGlobalInterrupts(); 00785 #endif 00786 /* All errors not being fatal at least must stop the current or requested task and put it in error mode. 00787 * (This cannot be an isr anymore, and all non fatal Os errors are about some task.) */ 00788 TtaskControlBlock * taskTCB = privTcbList(uiTaskNumber); 00789 /* Note that the task is terminated, but it's locks are not removed, since this is an error 00790 * condition, it is unclear what the result would be, so that this cannot be compared with 00791 * a normal terminate, in which case the user can take precautions for released blocks etc. */ 00792 taskTCB->uiTaskStatus = defBaseTerminatedTask; 00793 /* In case we may have a shared task, we must check if this was one and thus if we must 00794 * reset the ShareStatus. */ 00795 #if (defUseSharedStack == cfgTrue) 00796 /* In case all tasks are shared, we know that we must reset. */ 00797 #if (defAllSharedStack == cfgFalse) 00798 /* If not, we need the initial status of the task */ 00799 #if (defInitialStatusConstant == cfgTrue) 00800 /* if we are lucky that is a constant. */ 00801 Tuint08 uiInitialStatus = defInitialStatusFixed; 00802 #else 00803 /* if not, that must be read from flash. */ 00804 Tuint08 uiInitialStatus = portFlashReadStruc(TtaskDefinitionBlock,pxTDBlist[uiTaskNumber],Tuint08,uiInitialStatus); 00805 #endif 00806 /* Test if this task is a shared task. */ 00807 if ((uiInitialStatus & defInitialSharedGetMask) == defInitialSharePresent) 00808 #endif 00809 { /* If so, we must identify this shared task as shared. */ 00810 taskTCB->pcStackLevel = defStackEmpty; 00811 /* and then we know, since is was running, we must reset the share state. */ 00812 uiOsStatus = ((uiOsStatus & defShareStateSetMask) | defShareStateAbsent); } 00813 #endif 00814 /* If we are at a task, or at some operations within the OS that handle a specific task, 00815 * we can leave this method by asking for a task switch. This is not a normal return. 00816 * Note that in this case the AuxRegBit (if used) can be set. Here, that is not a problem 00817 * for there are no switching interrupts that can take place. */ 00818 if (!bReturn) { privEnterOS(defActionTaskStateSwitch); } 00819 /* Otherwise we are done, and return to the OS operations that generated the error. */ } 00820 00821 #endif 00822 00823 00824 #if (cfgCheckOsStack == cfgTrue) || (cfgCheckWatermarks == cfgTrue) 00825 00826 static void privCheckOsStackLevel(void) 00827 { /* We are going to check if we overflowed the Os Stack. We should only arrive here if we are 00828 * in OS space, i.e. if we are sure the stack pointer actually should be inside the OS stack. */ 00829 Taddress pStack; 00830 Tuint16 uiOsStackSize; 00831 /* Obtain the current stack pointer. */ 00832 privGetStack(pStack); 00833 /* Calculate the Stacksize, we have to distinguish between the different stack types. Note we 00834 * assumed the stack pointer points to the byte that will be written next, i.e. the stack pointer 00835 * is post decrement. */ 00836 #if (cfgSysStackGrowthUp == cfgTrue) 00837 uiOsStackSize = ((Tuint16) pStack - (Tuint16) &xOS.StackOS[0]); 00838 #else 00839 uiOsStackSize = ((Tuint16) &xOS.StackOS[(StackSizeOS)-1] - (Tuint16) pStack); 00840 #endif 00841 /* Now, we do not incorporate the StackSafety parameter into our calculation. That parameter is 00842 * used for task stacks only. And, besides that, the call to this function, i.e.. privCheckOsStack 00843 * costs two bytes extra anyway */ 00844 #if (cfgCheckWatermarks == cfgTrue) 00845 if (uiOsStackMax<uiOsStackSize) uiOsStackMax=uiOsStackSize; 00846 #endif 00847 #if (cfgCheckOsStack == cfgTrue) 00848 if (uiOsStackSize>(StackSizeOS)) { privShowError((fatOsStackOverflowed | errTaskStateNon), callIdSystem ,errNoInfo); } 00849 #endif 00850 } 00851 00852 #endif 00853 00854 00855 #if (cfgCheckWatermarks == cfgTrue) && (cfgSysReuseOsStack == cfgFalse) 00856 00857 static void privCheckOsStackRegion(void) 00858 { /* We are going to check which part of the stack space is used. Note, this routine is not capable 00859 * of detecting a stack overflow. In that case, it will simple see that the whole of the space 00860 * has been used. */ 00861 Taddress pStack; 00862 /* Start with the largest detectable stack size. */ 00863 Tuint08 uiOsStackSize = StackSizeOS; 00864 /* If the whole stack already has been used, there is nothing to check */ 00865 if (uiOsStackMax < uiOsStackSize) 00866 { /* Calculate the Stack size, we have to distinguish between the different stack types. */ 00867 #if (cfgSysStackGrowthUp == cfgTrue) 00868 /* Find the beginning of the stack. */ 00869 pStack = &xOS.StackOS[(StackSizeOS)-1]; 00870 /* loop downwards until we find the first used byte, or until we reach a previous boundary whatever comes first. */ 00871 while ((*(pStack--) == defStackInitByte) && ((uiOsStackSize--)>uiOsStackMax)); 00872 #else 00873 /* Find the beginning of the stack. */ 00874 pStack = &xOS.StackOS[0]; 00875 /* loop upwards until we find the first used byte, or until we reach a previous boundary whatever comes first. */ 00876 while ((*(pStack++) == defStackInitByte) && ((uiOsStackSize--)>uiOsStackMax)); 00877 #endif 00878 /* Load the new boundary. */ 00879 uiOsStackMax=uiOsStackSize; } } 00880 00881 #endif 00882 00883 00884 00885 #if (cfgCheckMethodUse == cfgTrue) && (defCapabilitiesFull == cfgFalse) 00886 00887 static void privCheckCapabilities(Tuint08 uiCallId, Tuint08 uiTaskCaps) 00888 { /* Use this function to see if the task is capable of the required functions. 00889 * The function is not needed if all tasks have full capabilities, for there is nothing 00890 * to check in that case. Note this function can only check the capabilities of the 00891 * current function. If we happen to be in isr space (genXXXX functions) the current 00892 * function has no meaning, and the check is omitted. */ 00893 Tuint08 uiTaskNumber; 00894 /* The current task has no meaning inside an isr, so there is nothing to check in that case */ 00895 if ((uiOsStatus & defContextGetMask) == defContextStateIsr) { return; } 00896 /* If no, extract the current task number. */ 00897 uiTaskNumber = (uiOsStatus & defTaskNumberGetMask) >> defOsTaskNumberShift; 00898 /* Get the capabilities of the task*/ 00899 Tuint08 uiDefinedCaps = portFlashReadByte(Tuint08,uiCapabilities[uiTaskNumber]); 00900 /* Check if the capabilities match, with ~ all non defined caps turn high, if it matches with a 00901 * required cap, this is an error. */ 00902 Tuint08 uiViolation = (uiTaskCaps & ~uiDefinedCaps); 00903 /* Thus if the value equals zero all required capabilities are present, otherwise some are absent. */ 00904 if (uiViolation != 0) 00905 { /* Determine the highest violation (binary log) */ 00906 Tuint08 uiInfo = 8; 00907 /* Check if this is the violating bit */ 00908 while ( (uiViolation & 0x80) == 0 ) 00909 { /* If not it could be bit 6, so we decrease the counter one ... */ 00910 uiInfo--; 00911 /* and shift the 6th bit to the 7th */ 00912 uiViolation <<= 1; } 00913 /* Report an error and stop the task if the requested capabilities are absent. The ControlTaskNumber 00914 * also contains the realm in which we currently are. */ 00915 privShowError((errInsufficientCapabilities | errTaskStateInfo | errOsStateAsIs), uiCallId, (uiInfo << errInfoNumberShift) | (uiTaskNumber << errTaskNumberShift)); } } 00916 00917 #endif 00918 00919 00920 #ifdef portInitContext 00921 00922 static Taddress privInitContext(Taddress pTaskStart, Taddress pStackTop, Tuint08 uiRegisterCount, Tuint08 uiInterruptStart) 00923 { /* Arrive here to set up the initial stack. Of course this is machine dependent, but not very 00924 * strongly. For 8 bits cpu's it is fairly general. Just place the return address, the registers 00925 * and the status. Here the values are just cleaned. If needed we can add a portInitConext call 00926 * on the basis of an option. */ 00927 Tuint16 uiStartAddress = (Tuint16) pTaskStart; 00928 /* At the bottom of the artificial stack the start address of each task is defined. This is a pointer 00929 * to your Loop code. */ 00930 *(pStackTop--) = (Tuint08) uiStartAddress; 00931 *(pStackTop--) = (Tuint08) (uiStartAddress >> 8); 00932 /* If we have a program counter of more than 16 bit, call instructions push three bytes 00933 * into the stack. We must take that into account. Unfortunately, i believe, gcc is not 00934 * able to handle pointer larger as 64K words in the current setting. Thus this will 00935 * effectively be zero, thus although you need something like 00936 * *(pStackTop--) = (Tuint08) (pTaskStart >> 16); 00937 * we will use: */ 00938 #if (defThreeByteAddress == cfgTrue) 00939 *(pStackTop--) = 0; 00940 #endif 00941 /* We rely upon register cleaning done by the Femto OS, or the precleaning done by privTaskInit(). */ 00942 pStackTop -= uiRegisterCount; 00943 /* The way the status register is setup depends on the state of the interrupts. These can be specified per task 00944 * or (easier, and shorter) in general. Note that the optimization is not needed in a strict sense, the variable 00945 * uiInterruptStart constrains the interrupt start information, even if this is constant for all tasks. But, of course, 00946 * the lower part generates shorter code. */ 00947 #if (defInterruptStartConstant == cfgFalse) 00948 /* If we specify the CPU status register per task, we need to prepare them per task. uiInterruptStart contains 00949 * the information about which interrupts must be activated. The other bits of the status register cannot be 00950 * set individually (there is no need in general) */ 00951 Tuint08 uiInitCPUStatusRegister = defInitCPUStatusRegister | (0 << portInitModeInterruptLoc); 00952 /* Test if global interrupts must be activated at the start, if so set the specified bit. */ 00953 #if (cfgIntGlobalOnly == cfgTrue) 00954 /* In case we have a mapping from tick interrupts on global interrupts, we require both interrupts 00955 * to be activated before activating the global interrupt. */ 00956 if ((uiInterruptStart & ((cfgGlobSet | cfgTickSet) & defInitialInterruptGetMask)) == ((cfgGlobSet | cfgTickSet) & defInitialInterruptGetMask)) { uiInitCPUStatusRegister |= (1 << portInitGlobalInterruptLoc); } 00957 #else 00958 /* Otherwise we just test the global interrupt setting. */ 00959 if ((uiInterruptStart & (cfgGlobSet & defInitialInterruptGetMask)) != defInitialInterruptAbsent) { uiInitCPUStatusRegister |= (1 << portInitGlobalInterruptLoc); } 00960 #endif 00961 /* Test if tick interrupts must be activated at the start, if so set the specified bit. */ 00962 #if (cfgIntTickTrack == cfgTrue) 00963 if ((uiInterruptStart & (cfgTickSet & defInitialInterruptGetMask)) != defInitialInterruptAbsent) { uiInitCPUStatusRegister |= (1 << portInitTickInterruptLoc); } 00964 #endif 00965 /* The status register is put at the end of the stack. (See portSaveContext for the reason why) */ 00966 *(pStackTop--) = uiInitCPUStatusRegister; 00967 #else 00968 /* Set up the status register with the initial interrupt states: global set and tick set */ 00969 #if (((defInterruptStartFixed) & cfgGlobSet) == cfgGlobSet) && (((defInterruptStartFixed) & cfgTickSet) == cfgTickSet) 00970 *(pStackTop--) = defInitCPUStatusRegister | (0 << portInitModeInterruptLoc) | (1 << portInitGlobalInterruptLoc) | (1 << portInitTickInterruptLoc); 00971 /* Set up the status register with the initial interrupt states: global set and tick clear */ 00972 #elif (((defInterruptStartFixed) & cfgGlobSet) == cfgGlobSet) && (((defInterruptStartFixed) & cfgTickClear) == cfgTickClear) 00973 #if (cfgIntGlobalOnly == cfgTrue) 00974 /* In case we have a mapping from tick interrupts on global interrupts, global interrupts cannot be activated if tick interrupts are not activated */ 00975 *(pStackTop--) = defInitCPUStatusRegister | (0 << portInitModeInterruptLoc) | (0 << portInitGlobalInterruptLoc) | (0 << portInitTickInterruptLoc); 00976 #else 00977 /* Default situation. */ 00978 *(pStackTop--) = defInitCPUStatusRegister | (0 << portInitModeInterruptLoc) | (1 << portInitGlobalInterruptLoc) | (0 << portInitTickInterruptLoc); 00979 #endif 00980 /* Set up the status register with the initial interrupt states: global clear and tick set */ 00981 #elif (((defInterruptStartFixed) & cfgGlobClear) == cfgGlobClear) && (((defInterruptStartFixed) & cfgTickSet) == cfgTickSet) 00982 *(pStackTop--) = defInitCPUStatusRegister | (0 << portInitModeInterruptLoc) | (0 << portInitGlobalInterruptLoc) | (1 << portInitTickInterruptLoc); 00983 /* Set up the status register with the initial interrupt states: global clear and tick clear */ 00984 #elif (((defInterruptStartFixed) & cfgGlobClear) == cfgGlobClear) && (((defInterruptStartFixed) & cfgTickClear) == cfgTickClear) 00985 *(pStackTop--) = defInitCPUStatusRegister | (0 << portInitModeInterruptLoc) | (0 << portInitGlobalInterruptLoc) | (0 << portInitTickInterruptLoc); 00986 #elif (defNumberOfTasks == 0) 00987 /* without tasks there is nothing to set. */ 00988 #else 00989 /* well, we never come here. */ 00990 #error "Parameter 'defInterruptStartFixed' is misspeld or incorrect (You should not arrive here)." 00991 #endif 00992 #endif 00993 /* Done, let the caller know where the stack ended. */ 00994 return pStackTop; } 00995 #endif 00996 00997 00998 static TtaskControlBlock * privTcbList(Tuint08 uiTaskNumber) 00999 { /* This method may not be called with defCurrentTaskNumber any longer. Unfortunately we 01000 * cannot check if we violate that, because that may corrupt stack in privInitOs(). 01001 * The location of the task control block is stored in flash, be careful, use the correct 01002 * instructions to retrieve it. */ 01003 return portFlashReadWord(TtaskControlBlock *,pxTCBlist[uiTaskNumber]); } 01004 01005 01006 static Tuint08 privTaskNumber(Tuint08 uiTaskNumber) 01007 { /* Check if we are interested in the current task */ 01008 if ((uiTaskNumber & defCurrentTaskMask) == defCurrentTaskNumber) 01009 { /* If yes, replace the uiTaskNumber with the current task number. */ 01010 uiTaskNumber = (uiOsStatus & defTaskNumberGetMask) >> defOsTaskNumberShift; } 01011 return uiTaskNumber; } 01012 01013 01014 #if (defRegisterUseConstant == cfgFalse) 01015 01016 static Tuint08 privRegisterCount(Tuint08 uiRegisterUse) 01017 { /* We want to count the number of register this uiRegisterUse byte represent. Each set bit 01018 * counts for four registers. */ 01019 /* uiCount accumulates the number of set bits */ 01020 Tuint08 uiCount = 0; 01021 /* Loop through all bits of the uiRegisterUse byte. Start with 'do' for the most optimal compiler result. */ 01022 do 01023 { /* Increase the counter if the bit is set by four since every bit represents four registers. */ 01024 if ((uiRegisterUse & 0x01) == 0x01) { uiCount+=4; } 01025 /* Shift to the next bit */ 01026 uiRegisterUse >>= 1; } 01027 while (uiRegisterUse); 01028 /* When uiRegisterUse equals zero there are no bits left. We are done. */ 01029 return uiCount; } 01030 01031 #endif 01032 01033 01034 static void privTaskInit(Tuint08 uiTaskNumber, Tuint08 uiInitControl) 01035 { /* Tasks are initialized in this routine. Note the fields: 01036 * uxDelay, siQueuLock, uiLoadCollect, uiLoadTotal, uiStackMax, uiRegisterUse 01037 * are not cleared when we re-initialize the task. Only about uxDelay there could 01038 * be debate since the would indicate the last wake time. But what is a last wake 01039 * time in this case. We could set it to the current time, but have not done so. */ 01040 /* Report that we are initializing this task. */ 01041 privTrace(traceTaskInit | uiTaskNumber); 01042 TtaskControlBlock * taskTCB = privTcbList(uiTaskNumber); 01043 /* In case we might return here due to a watchdog bark or a restart or so. some old connections 01044 * must be closed when present. */ 01045 #if (defReUseTaskInit == cfgTrue) 01046 /* And if asked for it. */ 01047 if ((uiInitControl & defInitLockGetMask) == defInitLockRelease) 01048 { /* In case we use synchronization and the watchdog or want to be able to manually restart a task 01049 * it may be that the task that has to be re-initiated is holding some locks. These must be released properly 01050 * We need only to release locks on other tasks that are held by this task. Since waits cannot be non-blocking 01051 * it can safely be ignored here. Hmm, some other task may call restart on a blocking task on wait. So it seems 01052 * better to always clean when synchronization is used. */ 01053 #if (cfgUseSynchronization != cfgSyncNon) 01054 /* we only need to check if the task contains a slot. */ 01055 if (uiTaskNumber < defNumberOfTasksWithSlot) 01056 { /* We may only enter here if the particular task indeed has a slot stack, otherwise there is nothing clean 01057 * If we made use of priority lifting, we do not need to do anything. We can simply clean the slot stack. */ 01058 privCleanSlotStack((TtaskExtendedControlBlock *) taskTCB ); 01059 /* and any task that may run freely now will be release by the call below. Please note that is not possible 01060 * that is call releases the present task, since all its slots have been wiped. */ 01061 #if ((defUseMutexes == cfgTrue) || (defUseQueus == cfgTrue)) 01062 privReleaseSyncBlockingTasks(); 01063 #endif 01064 } 01065 #endif 01066 /* At this point we must check if we have some kind of lock in the file system and we need 01067 * to release this and other tasks. Only include code if this is possible at all. */ 01068 #if (cfgUseFileSystem == cfgTrue) 01069 /* We can simply try to close a file. If no lock is hold and no blocks are present this method returns 01070 * without any harm done. Of course it is more overhead, but we assume this part of the code is rarely executed 01071 * and therefore we do not want to invest the bytes. There are quite a number of situations in which the task 01072 * can be caught when killed. All these situations are handled by the method. */ 01073 privPrepareFileClose(uiTaskNumber); 01074 #endif 01075 } 01076 #endif 01077 /* Read the priority the task will start with is contained in the lowest nibble this number, the start state 01078 * information is contained in the highest nibble. the interrupt state in both. While the handling for the 01079 * priority is simple, simply replace it or not, depending on the defInitStatusPrio, the start state 01080 * requires a more complex handling. Globally this routine provides the following services to the caller 01081 * (1) Load the start state from flash, this is the default action 01082 * (2) Load the start state from the uiInitControl, use defInitStatusCopyDo 01083 * (3) Load the start state from the uiInitControl, but allow for a fall back scenario for the default state 01084 * (4) Make sure that the start state is 'shared' instead of 'running' for shared tasks. 01085 * Apart from these facilities, it also provide a facility to set the shared state bit in 01086 * the OS status. If the task was running before, but is not running afterwards, this but must 01087 * be reset and vice versa. 01088 * First read the initial status from flash, or use a constant value. */ 01089 #if (defInitialStatusConstant == cfgTrue) 01090 Tuint08 uiInitialStatus = defInitialStatusFixed; 01091 #else 01092 Tuint08 uiInitialStatus = portFlashReadStruc(TtaskDefinitionBlock,pxTDBlist[uiTaskNumber],Tuint08,uiInitialStatus); 01093 #endif 01094 /* We can call this with a predefined state or with a default state, in which case we want to restart 01095 * like we started at the beginning. */ 01096 #if (defUseSharedStack == cfgTrue) || (includeTaskRestart == cfgTrue) 01097 /* Since the bit pattern of the default start state equals the one of the shared state, and since we 01098 * know we can never explicitly set the state to be shared from the outside (this is always a modified 01099 * running state) We must first test if we have a default state. */ 01100 if ((uiInitControl & defInitialStartGetMask) == defRestartDefault ) 01101 { /* We do not need to copy the start information from the uiInitControl if the caller asked for a default 01102 * If it is not equal, we leave leave the copy bit alone. Most of the time however, there will not 01103 * be a request for a copy, so this does nothing.*/ 01104 uiInitControl = (uiInitControl & defInitStatusCopySetMask) | defInitStatusCopyDont; } 01105 #endif 01106 /* If we have a suspend request, this will be honored at this place. This may override the previous 01107 * situation. Tasks cannot ignore a suspend request at this moment. Suspend requests are only possible 01108 * when genSuspend() is present: */ 01109 #if (includeGenSuspend == cfgTrue) 01110 /* test if the request has been made */ 01111 if ((taskTCB->defSusField & defSusGetMask) == defSusRequest) 01112 { /* if so, we must set the StatusCopy and the suspended restart: */ 01113 uiInitControl = (uiInitControl & (defInitStatusCopySetMask & defInitialStartSetMask)) | (defRestartSuspended | defInitStatusCopyDo); 01114 /* We do not need to clear the SusRequest separately since that is done below in 01115 * the clearance of the TaskMonitor. */ } 01116 #endif 01117 /* If we were running, and make use of a shared stack, we must inform the OS that we stopped a running 01118 * shared state (unless we continue to run, but that is not the default, and not possible in this routine) 01119 * This is however only needed if we are not actively are creating a context .*/ 01120 /* If we make use of shared tasks we must inform the OS about the situation. */ 01121 #if (defUseSharedStack == cfgTrue) 01122 /* And only if the current task is indeed a shared task */ 01123 #if (defAllSharedStack == cfgFalse) 01124 /* If all tasks are shared this test is always true, so skip it. */ 01125 if ((uiInitialStatus & defInitialSharedGetMask) == defInitialSharePresent) 01126 #endif 01127 { /* Retrieving the uiOsStatus is a costly operation, so lets work via a register 01128 * gcc optimization does not recognize this. */ 01129 Tuint08 uiStatusCopy = uiOsStatus; 01130 /* If so, we must test if we want to activate a shared task, if so we must create a context (see below) */ 01131 if ((uiInitControl & defInitSharedGetMask) == defInitSharedActive) 01132 { /* and set the shared bit of the OS status */ 01133 uiStatusCopy = ((uiStatusCopy & defShareStateSetMask) | defShareStateRunning); } 01134 else 01135 { /* Task that are not rescheduled right now need no context */ 01136 uiInitControl = (uiInitControl & defInitContextSetMask) | defInitContextKeep; 01137 /* Shared tasks that are not scheduled for running may not be in the shared mode, 01138 * but be put to sleep or be suspended from the outside. The only way to recognize 01139 * such tasks is at the stack level being zero. Other way around, if the stack 01140 * level does not equal zero, it must have been running, or been put to sleep/suspend 01141 * block while running, and is holding the share state. Since we are to passivy this 01142 * state, we clear the bit. */ 01143 if (taskTCB->pcStackLevel != defStackEmpty) 01144 { /* If so, we are stopping the only running shared task, and must inform the OS 01145 * so it can select a new one. */ 01146 uiStatusCopy = ((uiStatusCopy & defShareStateSetMask) | defShareStateAbsent); 01147 /* and make sure that the stack is empty so this is recognized */ 01148 taskTCB->pcStackLevel = defStackEmpty; } 01149 /* This is the place to correct the situation where we have asked for a running state 01150 * but we are going to get into a shared state, since a shared tasks can only be 01151 * in the running state when we have a valid context, ie.e on defInitContextRenew. 01152 * We need only to check the first bit of the state, since if it is set the second 01153 * must be set too, or if it is not, it is already in the shared state (what is a 01154 * defRestartDefault actually. */ 01155 if ((uiInitControl & defBaseStopStateGetMask) == defBaseStopStateGo ) 01156 { /* So we have requested for a defRestartRunning, change it to defRestartShared. */ 01157 uiInitControl = (uiInitControl & defBaseModeSetMask) | defBaseModeShared; } } 01158 /* Dont forget to put the copy back */ 01159 uiOsStatus = uiStatusCopy; } 01160 /* If we are putting a task to sleep, and that task happens to be a shared task, the sleep 01161 * instruction must be interpreted as a restart. However, this is only the case for shared 01162 * tasks. Therefore we have a special option to indicate this situation, which is only 01163 * uses for this special case. For regular tasks we want to leave this routine after 01164 * the specialties for shared tasks have been skipped. 01165 * Test if we have a low power sleep possibility */ 01166 #if (cfgUseLowPowerSleep == cfgTrue) 01167 /* If all tasks are shared, we do not test for the defInitialSharePresent thus we also 01168 * not have an alternative branch. We simply always have to test if we want to leave. */ 01169 #if (defAllSharedStack == cfgFalse) 01170 /* otherwise we will only perform the test below in case we are certain we have 01171 * a regular task. */ 01172 else 01173 #endif 01174 { /* if we have a regular task, but we wanted to process shared tasks only we are done. */ 01175 if ((uiInitControl & defInitProcessGetMask) == defInitProcessSharedOnly ) { return; } } 01176 #endif 01177 #endif 01178 /* The defInitStatus indicates if we want to prepare a new TaskStatus. This is needed upon first use, as it 01179 * contains the initial run state, its priority etc. The structure of the information is not identical to 01180 * the uiTaskStatus. The priority and start state are on the same location, but on the location if the lock bit, 01181 * the delay bit and the dress bit other information is stored. This must be corrected. For shared tasks, the 01182 * task starts in the shared mode. Upon first pass thats OK (no shared running, but if a running task is 01183 * modified to shared extra measures might be needed. In any case, a new or renewed task, is not blocked, 01184 * delayed of dominant, therefore we set those bits. */ 01185 Tuint08 uiIntialFilteredStatus = (uiInitialStatus & (defBaseBlockStateSetMask & defBaseDelayStateSetMask & defBaseDressSetMask) ) | (defBaseBlockStateFree | defBaseDelayStateWake | defBaseDressDone); 01186 /* Depending on the fact if we are able to return here we can directly set its initial state, or 01187 * we must be more careful. In case there is the possibility to return here: */ 01188 #if (defReUseTaskInit == cfgTrue) 01189 /* See what must be kept from the original status, and what must be read from flash. uiInitControl contains 01190 * a bit mask for those pieces we want to retain from the original task status. The default is to 01191 * read everything from flash except for the priority information. The start state may be overwritten 01192 * later on. */ 01193 if ((uiInitControl & defInitStatusPrioGetMask) == defInitStatusPrioKeep) 01194 { /* If we indeed must replace the priority, do so in the uiIntialFilteredStatus */ 01195 uiIntialFilteredStatus = (uiIntialFilteredStatus & defInitialPrioritySetMask) | (taskTCB->uiTaskStatus & defInitialPriorityGetMask); } 01196 /* In three situations we may ask for a copy of the start state from the uiInitControl parameter */ 01197 #if (defUseSharedStack == cfgTrue) || (includeTaskRestart == cfgTrue) || ((cfgUseTaskWatchdog == cfgTrue) && (includeGenSuspend == cfgTrue)) 01198 /* If we have a request for copying the start state from the control (this request may be from outside, 01199 * but is not valid for the a start state being defRestartDefault, in which case the copyDo was cleared 01200 * above */ 01201 if ((uiInitControl & defInitStatusCopyGetMask) == defInitStatusCopyDo) 01202 { /* Replace the first start bits by the bits given in the control parameter. */ 01203 uiIntialFilteredStatus = (uiIntialFilteredStatus & defBaseRestartSetMask) | (uiInitControl & defBaseRestartGetMask); } 01204 #endif 01205 #endif 01206 /* Set the newly prepared task status. */ 01207 taskTCB->uiTaskStatus = uiIntialFilteredStatus; 01208 /* Fields uiTaskMonitor is initialized. Usually the init bytes are 0x00. If we 01209 * have no watchdog and no TaskRestart/TaskRecreate we can only arrive here one time. If the init fields are 01210 * 0x00 so we may rely upon the cleaning of the .bss section to reset these fields. 01211 * In other cases however we must explicitly clean/initialize those fields. */ 01212 #if (defUseTaskMonitor == cfgTrue) && ((defReUseTaskInit == cfgTrue) || (defTaskMonitorInit != 0x00)) 01213 taskTCB->uiTaskMonitor = defTaskMonitorInit; 01214 #endif 01215 /* Fields uiTasksLevels is initialized. Usually the init bytes are 0x00. If we 01216 * have no watchdog and no TaskRestart/TaskRecreate we can only arrive here one time. If the init fields are 01217 * 0x00 so we may rely upon the cleaning of the .bss section to reset these fields. 01218 * In other cases however we must explicitly clean/initialize those fields. */ 01219 #if (defUseTaskLevels == cfgTrue) && ((defReUseTaskInit == cfgTrue) || (defTaskLevelsInit != 0x00)) 01220 taskTCB->uiTaskLevels = defTaskLevelsInit; 01221 #endif 01222 /* If we keep track of the watermarks we renew them when we renew the priority */ 01223 #if (defReUseTaskInit == cfgTrue) && (cfgCheckWatermarks == cfgTrue) 01224 /* ... Initializing the task may (requested through the call) require resetting those levels. */ 01225 if ((uiInitControl & defInitStatusPrioGetMask) == defInitStatusPrioRenew) 01226 { /* If so, clean the StackMax level and the use of the registers. */ 01227 taskTCB->uiStackMax = 0; 01228 taskTCB->uiRegisterUse = 0; } 01229 #endif 01230 /* We make a new context if this is a one time call, ... */ 01231 #if (defReUseTaskInit == cfgTrue) 01232 /* ... or if we specially ask for it ... */ 01233 if ((uiInitControl & defInitContextGetMask) == defInitContextRenew) 01234 #endif 01235 { /* Report that we are making the context of this task. */ 01236 privTrace(traceCreateContext); 01237 /* pcStackOffset is a pointer to the beginning of the stack of this task, it is located in flash. */ 01238 Taddress pcStackOffset = portFlashReadStruc(TtaskDefinitionBlock,pxTDBlist[uiTaskNumber],Taddress,pcStackOffset); 01239 /* We need the place where the task starts. This is placed on the context as return address. It is located in flash */ 01240 Taddress pTask = portFlashReadWord(Taddress,pxLooplist[uiTaskNumber]); 01241 /* Register compression requires information on which registers must be saved. Every bit stands for 01242 * four bits to save. If we make use of Register Compression with variable registers per task we must 01243 * load the information from flash. otherwise we just may use the constant here. 01244 * Here we count how may registers will be saved on the stack. For each register one byte will be reserved. 01245 * If all RegisterUse parameters are equal, we can calculate the number at compile time. */ 01246 #if (defRegisterUseConstant == cfgTrue) 01247 /* The constant defRegisterCount holds the number of registers used.*/ 01248 Tuint08 uiRegCount = defRegisterCount; 01249 #else 01250 /* The register use must be read from flash. */ 01251 Tuint08 uiRegisterUse = portFlashReadStruc(TtaskDefinitionBlock,pxTDBlist[uiTaskNumber],Tuint08,uiRegisterUse); 01252 /* We have to calculate the number dynamically */ 01253 Tuint08 uiRegCount = privRegisterCount(uiRegisterUse); 01254 #endif 01255 /* We need the StackSize if we must clean the stack before use */ 01256 #if (defStackClean == cfgTrue) 01257 /* Get the reserved stack space from flash, or use the constant if all stack sizes are identical Note that, if we 01258 * don't check, we don;t need the uiStackSize information. It is simply assumed there is enough. */ 01259 #if (defStackSizeConstant == cfgTrue) 01260 Tstack uiStackSize = defStackSizeFixed; 01261 #else 01262 Tstack uiStackSize = portFlashReadStruc(TtaskDefinitionBlock,pxTDBlist[uiTaskNumber],Tstack,uiStackSize); 01263 #endif 01264 #endif 01265 /* Clean the stack and set up the context. The method portInitContext makes room the return address. 01266 * the device status register and all registers used. */ 01267 #if (cfgSysStackGrowthUp == cfgTrue) 01268 /* First fill the whole stack with the defStackInitByte if needed */ 01269 #if (defStackClean == cfgTrue) 01270 Taddress pStackTop = pcStackOffset; 01271 while (uiStackSize--) { *(pStackTop++) = defStackInitByte; } 01272 #endif 01273 /* Subsequently define the context. */ 01274 taskTCB->pcStackLevel = (Tstack) ((Tuint16) portInitContext(pTask, pcStackOffset, uiRegCount, uiInitialStatus) - (Tuint16) pcStackOffset); 01275 #else 01276 /* First fill the whole stack with the defStackInitByte if needed */ 01277 #if (defStackClean == cfgTrue) 01278 Taddress pStackTop = pcStackOffset; 01279 while (uiStackSize--) { *(pStackTop--) = defStackInitByte; } 01280 #endif 01281 /* Subsequently define the context. */ 01282 taskTCB->pcStackLevel = (Tstack) ((Tuint16) pcStackOffset - (Tuint16) portInitContext(pTask, pcStackOffset, uiRegCount, uiInitialStatus)); 01283 #endif 01284 } } 01285 01286 01287 static void privEnterOS(Tuint08 uiAction) 01288 { /* This is the method to call to start the OS functions. Its is typically called from yield, 01289 * delay etc, but also from the switching api functions after the completed their task. The 01290 * action parameter states the intention of the caller. It contains whether or not we should 01291 * switch the task, and if a tick occurred. 01292 * Report that we are starting OS specific actions */ 01293 privTrace(traceOsStart); 01294 /* Now is the time to permanently set the status of the system to OS. */ 01295 uiOsStatus = ((uiOsStatus & defContextSetMask) | defContextStateOs); 01296 /* First we check if no event has taken place. */ 01297 #if (cfgUseEvents == cfgTrue) 01298 /* Handling events must take place in an protected environment. */ 01299 #if (cfgIntOsProtected == cfgFalse) 01300 privDisableGlobalInterrupts(); 01301 #endif 01302 /* Check if there are any event set */ 01303 if (portEventRegister != defAllEventsReset) 01304 { /* OK, we have to handle the events and possibly deblock some tasks. If we invert the Event 01305 * register, we have '1' on all places that must be left alone, and '0' on those places where 01306 * the bits may be reset. */ 01307 Tuint08 uiInvEvent = ~portEventRegister; 01308 /* Don't forget to reset the event register */ 01309 portEventRegister = defAllEventsReset; 01310 /* Loop through all tasks possibly waiting on an event. */ 01311 Tuint08 uiLoopTask; 01312 for (uiLoopTask=defTaskNumberEventBegin; uiLoopTask<defTaskNumberEventEnd; uiLoopTask++) 01313 { TtaskControlBlock * loopTCB = privTcbList(uiLoopTask); 01314 /* Test if the task is really waiting on events */ 01315 if (loopTCB->uiTaskEvents != defAllEventsReset) 01316 { /* reset all events that are fired */ 01317 loopTCB->uiTaskEvents &= uiInvEvent; 01318 /* Check if there are any events left. */ 01319 if (loopTCB->uiTaskEvents == defAllEventsReset) 01320 { /* If not, unblock this task. */ 01321 privUnblockTask(uiLoopTask | defParaLockStateUnlock | defParaRetStateTrue); 01322 /* If we have unblocked a task, we make sure we switch tasks asap */ 01323 /* TODO v0.90: If we are returning a full byte, it must not be possible to 01324 * switch the task since there will be only one return value register. */ 01325 uiAction |= defActionTaskStateSwitch; } } } } 01326 /* Done, restore interrupts if needed */ 01327 #if (cfgIntOsProtected == cfgFalse) 01328 privEnableGlobalInterrupts(); 01329 #endif 01330 #endif 01331 /* If we do not want to switch, we are quickly done. Note that time measurement is also 01332 * skipped, so, we may not skip this to often, often being a full round of the subticktimer. 01333 * Normally however, this is a one time action, because a regular entry over here due to 01334 * an interrupt will not skip this section. */ 01335 if ((uiAction & defActionTaskGetMask) == defActionTaskStateSwitch) 01336 { /* If we make use of a file system we must check if there is a task waiting for a burn lock 01337 * to finish (this can only be one task at most. */ 01338 #if (cfgUseFileSystem == cfgTrue) 01339 /* Look if we have a burn lock active, if so there must be a write lock too, so we do not need to check that. */ 01340 if ((uiFsStatus & defFsBurnBlockGetMask) == defFsBurnBlockActive) 01341 { /* If so we test if the file system is ready for a new byte to be written */ 01342 if (portFSWriteReady()) 01343 { /* Tell we may burn again. In this case we must clean the burn lock in the uiFsStatus, we do so below. */ 01344 privTrace(traceBurnFree); 01345 /* Check if we are just waiting for a FS release. In this situation there is no task 01346 * actually writing, but one of the write tasks was somehow terminated, and the system 01347 * must wait with the release of new tasks until the burn block is gone. */ 01348 if ((uiFsStatus & defFsReadBlockGetMask) == defFsReadBlockReleaseRequest) 01349 { /* Clear everything in the status register, except a possible request for sleep. */ 01350 uiFsStatus = (uiFsStatus & defFsFreeSetMask) | defFsFree; 01351 /* There could be other tasks waiting to be released and perform file operations. Always, directly 01352 * after a task completed its file operations, it must call for a release of new tasks. There is 01353 * no automatic dispatch mechanism to activate the tasks independently. */ 01354 privReleaseFileBlocks(); } 01355 else 01356 { /* We still have to clear the burn lock */ 01357 uiFsStatus = ((uiFsStatus & defFsBurnBlockSetMask) | defFsBurnBlockClear); 01358 /* In this case we are in a simple file write operation, so extract the task 01359 * that was waiting for burning. The Burn lock can not be active if no task is waiting, 01360 * which is essential since we have no task number indicating a 'free' state. We could check if that 01361 * task found has a write lock, but that should be the case */ 01362 #if (defUseFsOnMultipleTasks == cfgTrue) 01363 /* In the case of multiple tasks, the task that is currently writing is in the status */ 01364 Tuint08 uiLockTaskNumber = (uiFsStatus & defFsWriteNumberGetMask) >> defFsTaskNumberShift; 01365 #else 01366 /* otherwise it is a fixed number determined by the preprocessor. */ 01367 Tuint08 uiLockTaskNumber = defUseFsSingleTaskNumber; 01368 #endif 01369 /* we must unblock the task, note that 01370 * this kind of block (burn block) cannot timeout, and thus the function does not return a value 01371 * to indicate this, we must leave the return register as it was. Naturally we keep the lock, for 01372 * there could be more bytes that must be written. It is not possible for a terminated task 01373 * to arrive here, since the taskKill routine will always try to close a lock on the file. */ 01374 privUnblockTask(uiLockTaskNumber | defParaLockStateKeep | defParaRetStateNon); } } } 01375 #endif 01376 /* Well, let us first determine what kind of tick engine 01377 * we are running on. Since both types require quite a different approach the code is 01378 * completely separated. */ 01379 #if (cfgUseEquidistantTicks == cfgTrue) 01380 /* We are running equidistant ticks. Thus the timer interrupt is set to a fixed value and 01381 * can only be read, but not changed. Also, the timer is of the type interrupt and clear, thereby 01382 * guaranteeing the most regular tick intervals. But if we are in a full cooperative mode 01383 * i.e. all tick interrupts masked either by disabling tick interrupts itself, of by disabling 01384 * global interrupts, we do not see ticks-interrupts any more and have to check manually. */ 01385 #if (cfgIntManualTicks == cfgTrue) 01386 /* The check method returns true if a timer interrupt was due. The interrupt was also 01387 * cleaned and therefore we ask for a increase of the tick counter here. */ 01388 if (portCheckTimer()) { uiAction |= defActionTickStateTick; } 01389 #endif 01390 /* If we are checking timing issues or want to keep track of the load of the tasks we 01391 * must read the value timer. */ 01392 #if ( (cfgCheckTiming == cfgTrue) || (cfgUseLoadMonitor == cfgTrue) ) 01393 Tuint08 uiOsStartTime = portReadTimer(); 01394 #endif 01395 /* If we want to monitor the load, some calculations are needed. Please note that this facility 01396 * is only available when cfgIntOsProtected == true. Otherwise there is simply no way get the 01397 * data to the os, since during this calculation it may be interrupted also. */ 01398 #if (cfgUseLoadMonitor == cfgTrue) 01399 Tuint08 uiTaskTime; 01400 /* We want to calculate how much time the last task took. The subbyte contains the 01401 * last saved value of portReadTimer.*/ 01402 Tuint08 uiSubByte = uxTickCount.SubByte; 01403 /* It is possible that we had an interrupt since we saved the the subByte. We assume, 01404 * that in that case uiSubByte>uiOsStartTime. This may not be true if we had a very 01405 * long interrupt but that cannot be checked. We cannot check one full round of the timer, 01406 * since we do not want to spend bytes to keep track of that. 01407 * If, however the timer has an unhandled interrupt, we expect the portReadTimer() function 01408 * to return a timer value with cfgSysSubTicksPerFullTick added to the actual value. This 01409 * is 'easy' to implement. */ 01410 if (uiSubByte<=uiOsStartTime) 01411 /* If we have a very slow timer, we could arrive in the same subtick here, thus the equality 01412 * should result in the addition of zero subticks instead of cfgSysSubTicksPerFullTick. */ 01413 { uiTaskTime = uiOsStartTime - uiSubByte; } 01414 /* So here we past the cfgSysSubTicksPerFullTick barrier and must correct for the situation. */ 01415 else 01416 { uiTaskTime = cfgSysSubTicksPerFullTick - uiSubByte + uiOsStartTime; } 01417 /* If we have other interrupts at hand, the system may have spend some time there as well. We should 01418 * correct the uiTaskTime accordingly. Note that we cannot distinguish between different interrupts 01419 * of succeeding interrupts. */ 01420 #if (cfgIntUserDefined == cfgTrue) 01421 /* uiIsrLoadTemp holds the time spend in isr */ 01422 Tuint08 uiIsrTime = uiIsrLoadTemp; 01423 /* This time however was erroneously incorporated in the task time, so we must correct for that error, 01424 * again, we assume no multiple tick interrupts in between. The test in between it to make sure the 01425 * value is indeed deducible, which may not be the case in rare cases */ 01426 if (uiTaskTime > uiIsrTime) { uiTaskTime -= uiIsrTime; } 01427 /* Add it to the LoadCollect */ 01428 uiIsrLoadCollect += uiIsrTime; 01429 /* We have read out the value of uiIsrLoadTemp and must reset it for the next interrupt. */ 01430 uiIsrLoadTemp = 0; 01431 #endif 01432 /* Which task was running lately? */ 01433 TtaskControlBlock * oldTCB = privTcbList(privTaskNumber(defCurrentTaskNumber)); 01434 /* OK, this was the last task that did run, but ... did it run the very last slice or was it the 01435 * somewhat longer ago and did the idle time run after that? We can see the difference by looking 01436 * at uiAction variable. We did run a task (or isr) if we did not run the idle state. If we run the 01437 * idle state we must have come from privTickYield, the RunState and running mode. We only count the time if the task is running and the state 01438 * is still runnable (may be delayed). Of course we miss the time of those tasks which just went 01439 * blocking. Since there is no other way to find out, we have to accept this (small) error. */ 01440 if ((uiAction & defActionRunGetMask) == defActionRunStateTask) 01441 { /* The RunState is still set, so indeed the calculated time was due to the running of that task */ 01442 oldTCB->uiLoadCollect += uiTaskTime; } 01443 else 01444 { /* Now the last task was the idle task, so add the time to the idle collect. Btw we could 01445 * also have been sleeping that difference cannot be made. However, it does not matter, since the 01446 * time from wakeup until now could count for idle as well. The sleep time itself is lost.*/ 01447 uiIdleLoadCollect += uiTaskTime; } 01448 #endif 01449 /* Here we arrive at the first instruction when all checks are off. We increment the tick counter 01450 * if a timer interrupt has taken place. This is indicated the the uiAction parameter. Most times 01451 * we arrive here it is namely due to a yield of delay or so, and we can skip that step. */ 01452 if ((uiAction & defActionTickStateTick) == defActionTickStateTick) { privIncrementTick(); } 01453 /* DISCUSSION 01454 * Sometimes the GCC compiler uses a frame pointer when there is not real need. This costs a lot 01455 * of flash. With the measure below we try to convince gcc that a particular register is free. 01456 * This seems portable since it is a request the compiler may ignore. 01457 * See the explanation at the option for more information. */ 01458 #if (cfgSysFramePointerCounterMeasures == cfgTrue) 01459 register volatile Tuint08 uiAssignmentStatus asm ("r6"); 01460 #else 01461 Tuint08 uiAssignmentStatus; 01462 #endif 01463 /* The two most important steps of the scheduler are, incrementing the tick counter, and 01464 * determining which task has to run next. The former is done above, and this action possible 01465 * waked some tasks, the latter below. The switch context results in a new task to run, or 01466 * the idle task that may or, or the sleep mode that the device must be put in. */ 01467 uiAssignmentStatus = privSwitchContext(); 01468 /* First, we check if we are put to sleep, which is done in OS space btw. If we are to sleep, 01469 * we are not allowed to prepare a subbyte for timing measurement, since that variable is used 01470 * to pass the number of allowable tick blocks to sleep.*/ 01471 #if (cfgUseLowPowerSleep == cfgTrue) 01472 if ((uiAssignmentStatus & defAssignmentSleep) == defAssignmentSleep) 01473 { /* We indeed have to go to low power sleep. Enter the sleep mode, we do not return from this call. */ 01474 privEnterSleep(uxTickCount.SubByte); } 01475 #endif 01476 /* If we arrive here, we are left with two possibilities, either we go run a task or go to the 01477 * idle state. First however, we measure how long the OS took, since most tasks of the OS are 01478 * done by this time. */ 01479 #if ((cfgCheckTiming == cfgTrue) || (cfgUseLoadMonitor == cfgTrue)) 01480 Tuint08 uiOsTime; 01481 /* Read the timer again. */ 01482 Tuint08 uiOsStopTime = portReadTimer(); 01483 /* From the moment we filled uiOsStartTime until now, that is the time the 01484 * OS took to run. This may not even be one subtick, so the we must test for equality too. (i.e.. 01485 * both times being equal probably means not even one subtick, contrary to a full round of the 01486 * subtick timer */ 01487 if (uiOsStartTime <= uiOsStopTime) 01488 { uiOsTime = uiOsStopTime - uiOsStartTime; } 01489 else 01490 { /* Again, in this case the timer interrupt fired, but is not handled yet. Hmmm, I am not 01491 * even sure id this situation can happen, since this should be a hanging interrupt right? 01492 * Well anyway, it seems save to leave the calculation in anyway */ 01493 uiOsTime = cfgSysSubTicksPerFullTick - uiOsStartTime + uiOsStopTime; } 01494 /* If you already used half of the tick here, there is probably not enough time to complete 01495 * the following task. Let us calculate that situation. */ 01496 #if (cfgCheckTiming == cfgTrue) 01497 /* Since this may incidentally happen, and that does not cause problems 01498 * we calculate the continuous 4 sample average. Depending on how large that number can be 01499 * we need a 8 or 16 bit variable. */ 01500 #if (cfgSysSubTicksPerFullTick >= 64) 01501 Tuint16 uiOsLocalTimeAverage = ((Tuint16)uiOsTimeAverage + uiOsTimeAverage + uiOsTimeAverage + uiOsTime + 2); 01502 #else 01503 Tuint08 uiOsLocalTimeAverage = (uiOsTimeAverage + uiOsTimeAverage + uiOsTimeAverage + uiOsTime + 2); 01504 #endif 01505 /* The average value however should not exceed the a one byte value */ 01506 uiOsTimeAverage = (Tuint08) (uiOsLocalTimeAverage >> 2); 01507 /* If we have tracing activated, we report the actual timing and the averaged timing. 01508 * when they are close to the border*/ 01509 #if (cfgCheckTrace == cfgTrue) 01510 if (uiOsTimeAverage > (3*cfgSysSubTicksPerFullTick/8)) 01511 { privTrace(traceOsTime); 01512 privTrace(uiOsTime); 01513 privTrace(uiOsTimeAverage); } 01514 #endif 01515 /* If this value exceeds have the tick time, this should be reported. */ 01516 if (uiOsTimeAverage >= (cfgSysSubTicksPerFullTick / 2)) 01517 { /* This is a fatal error since it makes no sense to continue as this issue 01518 * will rise again and again. */ 01519 privShowError((fatOsTickRateTooHigh | errTaskStateNon), callIdSystem, errNoInfo ); } 01520 #endif 01521 #if (cfgUseLoadMonitor == cfgTrue) 01522 /* Having calculated the time spend in the OS, add it to the Collected times. */ 01523 uiOsLoadCollect += uiOsTime; 01524 /* In order to make the next time measurement possible save the last value read 01525 * from the timer in the Subbyte. That will be used to calculate the time spend in 01526 * a particular task. Of course we make a small error because the next few instructions 01527 * are not really part of the task. However, the same applies to the instructions 01528 * after the context save so we assume (hope?) these errors cancel out. */ 01529 uxTickCount.SubByte = uiOsStopTime; 01530 #endif 01531 #endif 01532 /* Now check if we must perform an idle task */ 01533 if ((uiAssignmentStatus & defAssignmentIdle) == defAssignmentIdle) 01534 { /* if so, call for the EnterIdle, from which we do not return */ 01535 privEnterIdle(); } 01536 /* Here we are done, the next thing is to enter the privEnterTask, in order to run 01537 * the task chosen */ 01538 #else 01539 /* We are running in the true time slice mode. Good choice, now you are sure that no tasks 01540 * are being starved if more are running full swing in one priority. OK, so far for the 01541 * advertisements. The timer interrupt is variable in this mode, and reset every time a task, 01542 * or the os starts. Note that the interrupts may be (and are) irregular. Ticks, however, 01543 * are on average, in pace with the system clock. */ 01544 Tuint08 uiTaskTime; 01545 /* Determining how long the task took is a snap, since the timer was reset just before 01546 * the task started. And, we must also specify how long we want to wait before the next 01547 * timer interrupt. Now that does not matter much here, since (tick) interrupts are disabled 01548 * anyhow. */ 01549 uiTaskTime = portReadAndResetTimer(defSubTicksMax); 01550 /* We assume the timer did not overflow. This may happen if you choose cfgSysSubTicksPerFullTick 01551 * too high. But you can easily check this, see below. In this timer model the subbyte collects 01552 * the subticks, from which the tick counter is driven. */ 01553 uxTickCount.SubByte += uiTaskTime; 01554 /* If we keep track of the task times, the only thing to do is to add uiTaskTime to the collector */ 01555 #if (cfgUseLoadMonitor == cfgTrue) 01556 /* If we have other interrupts at hand, the system may have spend some time there as well. We should 01557 * correct the uiTaskTime accordingly. Note that we cannot distinguish between different interrupts 01558 * of succeeding interrupts. */ 01559 #if (cfgIntUserDefined == cfgTrue) 01560 /* uiIsrLoadTemp holds the time spend in isr */ 01561 Tuint08 uiIsrTime = uiIsrLoadTemp; 01562 /* This time however was erroneously incorporated in the task time, so we must correct for that error, 01563 * again, we assume no multiple tick interrupts in between. The test in between it to make sure the 01564 * value is indeed deducible, which may not be the case in rare cases */ 01565 if (uiTaskTime > uiIsrTime) { uiTaskTime -= uiIsrTime; } 01566 /* Add it to the LoadCollect */ 01567 uiIsrLoadCollect += uiIsrTime; 01568 /* We have read out the value of uiIsrLoadTemp and must reset it for the next interrupt. */ 01569 uiIsrLoadTemp = 0; 01570 #endif 01571 /* Which task was running lately? */ 01572 TtaskControlBlock * oldTCB = privTcbList(privTaskNumber(defCurrentTaskNumber)); 01573 /* OK, this was the last task that did run, but ... did it run the very last slice or was it the 01574 * somewhat longer ago and did the idle time run after that? We can see the difference by looking 01575 * at uiAction variable. We did run a task (or isr) if we did not run the idle state. If we run the 01576 * idle state we must have come from privTickYield, the RunState and running mode. We only count the time if the task is running and the state 01577 * is still runnable (may be delayed). Of course we miss the time of those tasks which just went 01578 * blocking. Since there is no other way to find out, we have to accept this (small) error. */ 01579 if ((uiAction & defActionRunGetMask) == defActionRunStateTask) 01580 { /* The RunState is still set, so indeed the calculated time was due to the running of that task */ 01581 oldTCB->uiLoadCollect += uiTaskTime; } 01582 else 01583 { /* Now the last task was the idle task, so add the time to the idle collect. Btw we could 01584 * also have been sleeping that difference cannot be made. However, it does not matter, since the 01585 * time from wakeup until now could count for idle as well. The sleep time itself is lost.*/ 01586 uiIdleLoadCollect += uiTaskTime; } 01587 #endif 01588 /* in this timing model we always call privIncrementTick() since the ticks added to the tick counter 01589 * are deduced from the value of subbyte */ 01590 privIncrementTick(); 01591 /* DISCUSSION 01592 * Sometimes the GCC compiler uses a frame pointer when there is not real need. This costs a lot 01593 * of flash. With the measure below we try to convince gcc that a particular register is free. 01594 * This seems portable since it is a request the compiler may ignore. 01595 * See the explanation at the option for more information. */ 01596 #if (cfgSysFramePointerCounterMeasures == cfgTrue) 01597 register volatile Tuint08 uiAssignmentStatus asm ("r6"); 01598 #else 01599 Tuint08 uiAssignmentStatus; 01600 #endif 01601 /* The two most important steps of the scheduler are, incrementing the tick counter, and 01602 * determining which task has to run next. The former is done above, and this action possible 01603 * waked some tasks, the latter below. The switch context results in a new task to run, or 01604 * the idle task that may or, or the sleep mode that the device must be put in. */ 01605 uiAssignmentStatus = privSwitchContext(); 01606 /* First, we check if we are put to sleep, which is done in OS space btw. If we are to sleep, 01607 * we are not allowed to prepare a subbyte for time measurement, since that variable is used 01608 * to pass the number of allowable tick blocks to sleep.*/ 01609 #if (cfgUseLowPowerSleep == cfgTrue) 01610 if ((uiAssignmentStatus & defAssignmentSleep) == defAssignmentSleep) 01611 { /* We indeed have to go to low power sleep. Enter the sleep mode, we do not return from this call. */ 01612 privEnterSleep(uxTickCount.SubByte); } 01613 #endif 01614 /* If we arrive here, we are left with two possibilities, either we go run a task or go to the 01615 * idle state, Now check if we must perform an idle task .*/ 01616 if ((uiAssignmentStatus & defAssignmentIdle) == defAssignmentIdle) 01617 { /* if so, first set the Timer with the right time for the idle task, which at the same time 01618 * returns the time spend so far in OS */ 01619 Tuint08 uiOsTime = portReadAndResetTimer(TimeSliceIdleTime); 01620 /* This is of course time spend, so must be added to the tick counter */ 01621 uxTickCount.SubByte += uiOsTime; 01622 /* If we monitor the load */ 01623 #if (cfgUseLoadMonitor == cfgTrue) 01624 /* the time spend in OS must be added to the appropriate collector */ 01625 uiOsLoadCollect += uiOsTime; 01626 #endif 01627 /* End we may enter the idle task. In this case we do not have the opportunity to check 01628 * upon the OS time. */ 01629 privEnterIdle(); } 01630 /* Arriving here means we are going to perform a regular task. So we must prepare the timers 01631 * for that.*/ 01632 Tuint08 uiTimeSlice; 01633 /* We have two options. Either we have specified the time slice for each task separately, or 01634 * we use the one fits all model. */ 01635 #if (defTimeSliceConstant == cfgFalse) 01636 /* Get the task number we choose to run next */ 01637 Tuint08 uiTaskNumber = privTaskNumber(defCurrentTaskNumber); 01638 /* Get the value of the time slice from flash */ 01639 uiTimeSlice = portFlashReadStruc(TtaskDefinitionBlock,pxTDBlist[uiTaskNumber],Tuint08,uiTimeSlice); 01640 #else 01641 /* In the standard model, we give all tasks the same value, */ 01642 uiTimeSlice = defTimeSliceFixed; 01643 #endif 01644 /* The time has come to determine how long the OS has run, reset the timer and set the new time slice */ 01645 Tuint08 uiOsTime = portReadAndResetTimer(uiTimeSlice); 01646 /* The time spend in the OS must be added to the extended tick counter */ 01647 uxTickCount.SubByte += uiOsTime; 01648 /* And, if we monitor the load ... */ 01649 #if (cfgUseLoadMonitor == cfgTrue) 01650 /* to the collector of the OS load time as well */ 01651 uiOsLoadCollect += uiOsTime; 01652 #endif 01653 /* Many things can go wrong with the timing, so the moment has come to check. */ 01654 #if (cfgCheckTiming == cfgTrue) 01655 /* First, check if the time spend in the OS does not exceed one tick. Although it is not an error in the 01656 * strictest sense, it can do harm to the collected subticks in the subbyte, which may overflow, since 01657 * it cannot be cleaned on this point. Since this may incidentally happen, and that does not cause 01658 * problems we calculate the continuous 4 sample average. */ 01659 #if (cfgSysSubTicksPerFullTick >= 64) 01660 Tuint16 uiOsLocalTimeAverage = ((Tuint16)uiOsTimeAverage + uiOsTimeAverage + uiOsTimeAverage + uiOsTime + 2); 01661 #else 01662 Tuint08 uiOsLocalTimeAverage = (uiOsTimeAverage + uiOsTimeAverage + uiOsTimeAverage + uiOsTime + 2); 01663 #endif 01664 /* The average value however should not exceed the a one byte value */ 01665 uiOsTimeAverage = (Tuint08) (uiOsLocalTimeAverage >> 2); 01666 /* If we have tracing activated, we report the actual timing and the averaged timing. 01667 * when they are close to the border*/ 01668 #if (cfgCheckTrace == cfgTrue) 01669 if (uiOsTimeAverage > (3*cfgSysSubTicksPerFullTick/8)) 01670 { privTrace(traceOsTime); 01671 privTrace(uiOsTime); 01672 privTrace(uiOsTimeAverage); } 01673 #endif 01674 /* If this value exceeds have the tick time, this should be reported. */ 01675 if (uiOsTimeAverage >= (cfgSysSubTicksPerFullTick / 2)) 01676 { /* This is a fatal error since it makes no sense to continue as this issue 01677 * will rise again and again. */ 01678 privShowError((fatOsTickRateTooHigh | errTaskStateNon), callIdSystem, errNoInfo ); } 01679 /* Second, we test if there is enough room for the current time slice, i.e. if the subtick counter will 01680 * not overflow, even if the task runs its full length. The comparison seams awkward, but makes use 01681 * of the overflow of the unsigned integers arithmetic. */ 01682 if (((Tuint08)(uiTimeSlice + uxTickCount.SubByte)) < uiTimeSlice) 01683 { /* if it does not fit report the error, we are in OS space and return automatically. */ 01684 privShowError((errTaskTakesTooLong | errTaskStateCurrent | errOsStateAsIs), callIdSystem, errCurrentTask ); 01685 /* We have a problem, since the task is put in error mode we cannot start it any more, that 01686 * would violate assumptions on running tasks. But we cannot select an other task at this point either. 01687 * The only senseable thing to do seems like launching the idle task, just for one slice. 01688 * Of course we must add the subticks already past */ 01689 uxTickCount.SubByte += portReadAndResetTimer(TimeSliceIdleTime); 01690 /* and start the idle task: */ 01691 privEnterIdle(); } 01692 #endif 01693 /* Here we are done, the next thing is to enter the privEnterTask, in order to run 01694 * the task chosen */ 01695 #endif 01696 } 01697 /* make it so */ 01698 privEnterTask(); } 01699 01700 01701 static void privIncrementTick(void) 01702 { /* This the place where the tick counter is increased. This may be one or more ticks, depending of 01703 * the timing model in use. */ 01704 #if (cfgUseEquidistantTicks == cfgFalse) 01705 /* Only in case we have true time slice model, more than one tick may be needed to add. For every 01706 * tick we fully loop the routine below. This is a little inefficient, but ensures we do not miss 01707 * a tick in the delay/wake section. If we do, we may miss to reactivate a delay task. */ 01708 while (uxTickCount.SubByte >= cfgSysSubTicksPerFullTick) 01709 #endif 01710 { /* In case of true time slicing we use the SubByte to collect all subticks, otherwise there is 01711 * no need */ 01712 #if (cfgUseEquidistantTicks == cfgFalse) 01713 uxTickCount.SubByte -= cfgSysSubTicksPerFullTick; 01714 #endif 01715 /* Every time we arrive here we must increase the tick counter by one. Or we arrived here because 01716 * subbyte overflowed the cfgSysSubTicksPerFullTick or we arrived here because we were send here 01717 * from a tick interrupt. */ 01718 ++uxTickCount.LowByte; 01719 /* Call the tick hook. Please note that at this point the tick counter is incomplete, */ 01720 #if (callAppTick00 == cfgTrue) 01721 appTick00(); 01722 #endif 01723 01724 /* if the low byte overflows ... */ 01725 if (uxTickCount.LowByte == 0 ) 01726 { /* ... Increase the high byte */ 01727 ++uxTickCount.HighByte; 01728 /* every 256 ticks we must call the tick08 hook */ 01729 #if (callAppTick08 == cfgTrue) 01730 appTick08(); 01731 #endif 01732 /* Once ever 256 ticks let us adjust the Os stack watermark */ 01733 #if (cfgCheckWatermarks == cfgTrue) && (cfgSysReuseOsStack == cfgFalse) 01734 privCheckOsStackRegion(); 01735 #endif 01736 /* If we have tracing activated we must regularly inform the outside world about 01737 * the status of the watermarks and registeruse. */ 01738 #if (cfgCheckWatermarks == cfgTrue) && (cfgCheckTrace == cfgTrue) 01739 if ((uxTickCount.HighByte & 0x03) == 0) { privTraceWatermarks(); } 01740 #endif 01741 /* every 256*256 ticks we must call the appTick16 hook */ 01742 #if (callAppTick16 == cfgTrue) 01743 if (uxTickCount.HighByte == 0) { appTick16(); } 01744 #endif 01745 /* On every cross of the low byte boundary, new tasks may have entered the near wake 01746 * state, thus we must set the corresponding bit. */ 01747 uiOsStatus = ((uiOsStatus & defNearWakeStateSetMask) | defNearWakeStatePresent); 01748 /* If we make use of the watchdog facility */ 01749 #if (cfgUseTaskWatchdog == cfgTrue) 01750 /* we test if we already arrived at a watchdog decrease boundary. This test simple passes when 01751 * the HighByte ends with the number of zeros given by cfgNumWatchdogDiv */ 01752 if ( (uxTickCount.HighByte & (0xFF >> (8 - cfgNumWatchdogDiv))) == 0) 01753 { /* if so, now loop trough all tasks who might have a watchdog */ 01754 Tuint08 uiLoopTask; 01755 for (uiLoopTask=defTaskNumberWatchdogBegin; uiLoopTask<defTaskNumberWatchdogEnd; uiLoopTask++) 01756 { TtaskControlBlock * loopTCB = privTcbList(uiLoopTask); 01757 /* We may only decrease the watchdog state of running tasks, If a task is delayed, suspended 01758 * or otherwise blocked, it can never feed its watchdog so we should not decrease its counter. */ 01759 if (loopTCB->uiTaskStatus >= defBaseRunningTask) 01760 { /* Extract the value of the watchdog counter which can only take four states */ 01761 Tuint08 uiWatchdog = loopTCB->defDogField & defDogGetMask; 01762 /* The value of zero (defDogDead) means we do not use the watchdog, the value one (defDogBark) means 01763 * it is already barking, so it should not be decreased further rendering it inactive,*/ 01764 if (uiWatchdog > defDogBark) 01765 { /* so only on higher values, decrease its value, which may result in a barking watchdog */ 01766 loopTCB->defDogField = (loopTCB->defDogField & defDogSetMask) | (uiWatchdog - defDogDec); } } } } 01767 #endif 01768 /* If we make use of the load monitor facility */ 01769 #if (cfgUseLoadMonitor == cfgTrue) 01770 /* we test if we already arrived at a watchdog monitor boundary. This test simple passes when 01771 * the HighByte ends with the number of zeros given by cfgNumMonitorDiv, we must 01772 * copy all values from the collectors to the totals. */ 01773 if ( (uxTickCount.HighByte & (0xFF >> (8 - cfgNumMonitorDiv))) == 0) { privCopyLoad(); } 01774 #endif 01775 /* This concludes the activity on the high byte (256 ticks) boundary */ 01776 } 01777 /* Let us check the OS stack on this place, just to be sure. */ 01778 #if (cfgCheckOsStack == cfgTrue) || (cfgCheckWatermarks == cfgTrue) 01779 privCheckOsStackLevel(); 01780 #endif 01781 #if (defUseDelay == cfgTrue) 01782 /* Now we must check if we must wake some delayed tasks, this only is the case when we 01783 * have near wakes. The mechanism of near wakes is made in order not to have to check all 01784 * tasks on every tick */ 01785 if ((uiOsStatus & defNearWakeStateGetMask) == defNearWakeStatePresent) 01786 { Tuint08 uiNearWakeCount = 0; 01787 Tuint08 uiLoopTask; 01788 /* we must find out which tasks are near wake, thus we must check all tasks */ 01789 for (uiLoopTask=defTaskNumberDelayBegin; uiLoopTask<defTaskNumberDelayEnd; uiLoopTask++) 01790 { TtaskControlBlock * loopTCB = privTcbList(uiLoopTask); 01791 /* We check if the task is delayed. Note that it need not to be running. If the task was suspended or 01792 * sleeping while delayed, this delay simply ends, but the task remains suspended/sleeping. The same 01793 * applies for killed tasks. Tasks that are blocked may have a timeout, so this must be checked as well. */ 01794 if ((loopTCB->uiTaskStatus & defBaseDelayStateGetMask) == defBaseDelayStateDelayed) 01795 { /* a task from which the high byte does not much is not near wake */ 01796 if (loopTCB->uxDelay.HighByte == uxTickCount.HighByte) 01797 { /* if it matches, we assume that the task must be waked, since we do not allow so long delays that the 01798 * end time is, after overflow, just before the current time in the same block. (The need for this has 01799 * several reasons, one of which is that this allows us to skip ticks within a tick block. It is needed 01800 * for recovery from low power sleep too. The former facility is not really used right now */ 01801 if (loopTCB->uxDelay.LowByte <= uxTickCount.LowByte) 01802 { /* We have a winner, we may give a wakeup call, but first we check synchronization */ 01803 privWakeupFromDelay(uiLoopTask,loopTCB); } 01804 else 01805 { /* arriving here means the particular task has a wake time in the near future, thus we may 01806 * increase the near wake counter. */ 01807 ++uiNearWakeCount; } } } } 01808 /* If we had no more near wakes we may clear the near wake bit. If we do not do this, it remains set, as 01809 * it was for certain when arriving here. If we clear the bit will be set again when we enter the 01810 * next tick block. */ 01811 if (uiNearWakeCount==0) { uiOsStatus = ((uiOsStatus & defNearWakeStateSetMask) | defNearWakeStateAbsent); } } 01812 #endif 01813 } } 01814 01815 01816 static Tselect privSelectTask(Tuint08 uiFlipMask, Tuint08 uiLoopStart, Tuint08 uiLoopEnd) 01817 { Tselect result; 01818 Tuint08 uiLoopTask; 01819 /* Since this is on if the deeper calls, we perform an OS stack check here when timing 01820 * is activted, (without timing activated, it is done inside privTcbList. */ 01821 #if (cfgCheckOsStack == cfgTrue) || (cfgCheckWatermarks == cfgTrue) 01822 privCheckOsStackLevel(); 01823 #endif 01824 /* Tselect contains of (MaxTask,Prio) MaxTask is variable which will hold the task with the highest 01825 * priority. The Prio is* the important variable. It is set to the highest priority of a non runnable task, 01826 * the default so to say. If it is not increased, we have no runnable task, thus we must run the idle task. 01827 * By using this approach we do not need a real idle task, with stack and so. */ 01828 result.MaxStatus = defBaseRunningTask - 1; 01829 /* Now loop trough all tasks and determine which has the highest priority. Since the 01830 * priority information is just before the bit 0, which determines the run state, all 01831 * tasks with equal priority are issued round robin. Tasks with a status below defRunableTask 01832 * will never be started, they are typically the blocked, delayed suspended, error or 01833 * sleeping tasks. */ 01834 for (uiLoopTask=uiLoopStart; uiLoopTask<uiLoopEnd; uiLoopTask++) 01835 { TtaskControlBlock * loopTCB = privTcbList(uiLoopTask); 01836 Tuint08 uiCompareStatus = loopTCB->uiTaskStatus ^ uiFlipMask; 01837 /* The 'smaller sign' is important here, only if the priority exceeds the smallest possible 01838 * runnable task a replacement must take place. */ 01839 if (result.MaxStatus < uiCompareStatus) 01840 { /* this is the most important task so far */ 01841 result.MaxTask = uiLoopTask; 01842 /* and this is its priority */ 01843 result.MaxStatus = uiCompareStatus; } } 01844 /* Return the result. Note that MaxTask in not initialized when there where not runnable tasks. */ 01845 return result; } 01846 01847 #if (cfgUseHierarchicalRoundRobin == cfgTrue) 01848 static void privMakeTasksRunable(Tuint08 uiFlipMask, Tuint08 uiPriority, Tuint08 uiLoopStart, Tuint08 uiLoopEnd, Tbool bCheckSkip) 01849 #else 01850 static void privMakeTasksRunable(Tuint08 uiFlipMask, Tuint08 uiLoopStart, Tuint08 uiLoopEnd, Tbool bCheckSkip) 01851 #endif 01852 { Tuint08 uiLoopTask; 01853 /* In fact we need only to restore the run state of the current priority. It 01854 * is however more work to check the priority, and it does not matter that we 01855 * reset the run states of all lower priorities as well. Since it could matter in 01856 * special cases where one particular lower priority task revives higher priority 01857 * tasks, which, when done, get to the same lower priority task every time, 01858 * thereby skipping the other lower priority tasks. If this is the case choose 01859 * for hierarchical round robin. However, we must take care that only running 01860 * tasks are handled. For the blocking tasks the dressbit is used for other 01861 * purposes. */ 01862 for (uiLoopTask=uiLoopStart; uiLoopTask<uiLoopEnd; uiLoopTask++) 01863 { /* So get the task ... */ 01864 TtaskControlBlock * loopTCB = privTcbList(uiLoopTask); 01865 /* Test if may have a blocking of some kind. */ 01866 /* If so make sure the present task is not blocked. */ 01867 if ((bCheckSkip) || ((loopTCB->uiTaskStatus ^ uiFlipMask) >= defBaseNoBlocksTask)) 01868 { /* ... and set the RunState to Runable If we make use of HierarchicalRoundRobin */ 01869 #if (cfgUseHierarchicalRoundRobin == cfgTrue) 01870 /* We may only reset those tasks in the requested priority. (Note we test the shifted priority because it 01871 * is faster on this side and on the callers side.) */ 01872 if ((loopTCB->uiTaskStatus & defBasePrioGetMask) == uiPriority) 01873 #endif 01874 { loopTCB->uiTaskStatus = (loopTCB->uiTaskStatus & defBaseDressSetMask) | defBaseDressRunable; } } } } 01875 01876 01877 static Tuint08 privSwitchContext(void) 01878 { /* We arrive here when we may want to do a context switch. If we do not want to switch, we are 01879 * always running a task, so that is the default return state. Here we fill in in, so we can 01880 * modify it to our needs. */ 01881 Tuint08 uiContextResult = defAssignmentTask; 01882 /* ... determine which task was running */ 01883 #if (cfgUseTaskWatchdog == cfgTrue) || (includeTaskProtectSwitchTasks == cfgTrue) || (includeTaskProtectSwitchCritical == cfgTrue) 01884 Tuint08 uiOldTaskNumber = privTaskNumber(defCurrentTaskNumber); 01885 TtaskControlBlock * oldTCB = privTcbList(uiOldTaskNumber); 01886 #endif 01887 /* DISCUSSION 01888 * Where to put he watchdog check was a matter of considerable inner debate of mine. Is the 01889 * privSwitchContext the right place? In any case, we must not do it after we determined 01890 * what the next task to run will be. We could have done it in the privInitOS, probably it 01891 * results in smaller code over there. On the other side, we want to keep privInitOS as lean as 01892 * possible by itself. We could have done it in privSwitchContext since there is no need 01893 * to check broken tasks after. In any case, a call to privTaskInit eats a lot of stack so 01894 * we want to do it at a place where the stack is fresh. Anyway i decided that this place 01895 * is not that bad. */ 01896 /* If we make use of the watchdog ... */ 01897 #if (cfgUseTaskWatchdog == cfgTrue) 01898 /* check if the watchdog barked (in this way we make sure we only check tasks which 01899 * actually did run, so at least had a chance to feed the watchdog. A blocking task 01900 * therefore should not be barking. Exception is, if the task just called for some 01901 * unavailable slot, and went blocking as last action. Likewise, the task could also be 01902 * delayed as last action (the task normally is started with bark activated as last 01903 * action, since bark is only checked upon tasks that have run.) Furthermore, a 01904 * terminated task can only issue a bark if it was not stuck but running without 01905 * watchdog feeding. This situation is extremely rare, but not impossible. Such a 01906 * task should stay terminated. End of the story, we have to recheck if the task is 01907 * indeed still running. Test if the task is running and if the watchdog barks. */ 01908 if ( (oldTCB->uiTaskStatus >= defBaseRunningTask) && ((oldTCB->defDogField & defDogGetMask) == defDogBark)) 01909 { /* Report that the watchdog is barking. The task number can be deduced from the following TaskInit report. */ 01910 privTrace(traceWatchdog); 01911 /* If so get the pointer to the bark code from flash, and call it, if there is something to call. 01912 * We first call the Bark and reinitialize afterwards in order to process suspend requests, 01913 * from the bark routine. This further has the advantage that the bark routine may inspect 01914 * the malicious task, before it is erased. */ 01915 #if (callAppBark == cfgTrue) 01916 portFlashReadWord(fpBarkTask,pxBarklist[uiOldTaskNumber-defTaskNumberWatchdogBegin])(); 01917 #endif 01918 /* Re-initialize the task, (but keep its priority). The rest of the state will be restored as if 01919 * the task was created for the first time. All hold locks will be released, blocking and delays 01920 * are removed, with out exception. The task could be in block waiting for the burnbock to release. 01921 * We want to keep the status partially (priority etc) and the watermarks. Shared tasks are put 01922 * back in the pool of waiting shared tasks. */ 01923 privTaskInit(uiOldTaskNumber,(defInitContextRenew | defInitStatusCopyDont | defInitSharedPassive | defInitStatusPrioKeep | defInitLockRelease | defInitProcessAll)); 01924 /* In case we check timing we must inform the caller that we may have spend considerable time in 01925 * the watchdog routine. Since this is a one time event (or should be rare at least, is is better 01926 * if it not triggers an error. */ 01927 #if (cfgCheckTiming == cfgTrue) 01928 uiContextResult |= defAssignmentWatchdog; 01929 #endif 01930 } 01931 #endif 01932 /* ... its state to done. If we previously run the idle task, the old task is already 01933 * done, but that does not matter. Since the dress runnable bit has only the runnable meaning 01934 * when the state is indeed not blocked (running, may be delayed) we may only set it to 01935 * done in that case. In blocking situations the bit is used for different purposes. 01936 * So there tasks must be skipped. We can save some bytes if there is no possibility for 01937 * blocking states. */ 01938 /* TODO v0.90 Calls on the heap may block also */ 01939 /* If we have shared tasks in our midst, ... */ 01940 #if (defUseSharedStack == cfgTrue) 01941 Tselect uiShareSelect; 01942 /* ... we must check if one of them is actually running. */ 01943 if ((uiOsStatus & defShareStateGetMask) == defShareStateAbsent) 01944 { /* If this is not the case, we must select a new task from the shared tasks pool. This 01945 * selection is based on round robin among all shared tasks, where we always select 01946 * the one with the highest priority. This selection equals the regular task selection 01947 * scheme, with only the access bit being different. (The bit being zero on shared 01948 * tasks. By flipping this bit in the selection we get the correct shared task.*/ 01949 uiShareSelect = privSelectTask((defBaseSharedGetMask & ~defBaseSharedTask),defTaskNumberSharedBegin,defTaskNumberSharedEnd); 01950 /* Now, we must see if there is indeed one that can be scheduled. Note that shared 01951 * tasks can be delayed as regular tasks, and they are not selected as long as this 01952 * delay is not over. The MaxStatus contains the states of the selected task with (!) 01953 * the flipped bit. So it looks like a stated that is able not blocked and not delayed. 01954 * Therefore compare with the highest state that could not run, if there are unequal, 01955 * we have a truly runnable state. */ 01956 if (uiShareSelect.MaxStatus != (defBaseRunningTask - 1)) 01957 { /* OK, among the shared tasks we have a winner! This task will be promoted to running 01958 * later on, get the control block of that task. */ 01959 TtaskControlBlock * shareTCB = privTcbList(uiShareSelect.MaxTask); 01960 /* But it could be that all shared tasks have completed their round robin, We have 01961 * to test this and that can be easily seen from the dressing. Only if all shared 01962 * states are defBaseDressDone, one of them get selected. */ 01963 if ((shareTCB->uiTaskStatus & defBaseDressGetMask) == defBaseDressDone) 01964 { /* In fact we need only to restore the run state of the shared states of the current 01965 * priority. We do so if we have cfgUseHierarchicalRoundRobin activated, mostly however 01966 * it does not matter much, so e save the code. See also the discussion below. 01967 * We do have to take care that we only reset shared states however */ 01968 #if (cfgUseHierarchicalRoundRobin == cfgTrue) 01969 privMakeTasksRunable((defBaseSharedGetMask & ~defBaseSharedTask),(shareTCB->uiTaskStatus & defBasePrioGetMask),defTaskNumberSharedBegin,defTaskNumberSharedEnd,(defDenseSharedStack == cfgTrue)); 01970 #else 01971 privMakeTasksRunable((defBaseSharedGetMask & ~defBaseSharedTask),defTaskNumberSharedBegin,defTaskNumberSharedEnd,(defDenseSharedStack == cfgTrue)); 01972 #endif 01973 } 01974 /* Ok, now we must initialize the context for this new state, keeping everything else as is. The 01975 * initialization in the function taskes also case of activation of the shared state in the uiOsStatus */ 01976 privTaskInit(uiShareSelect.MaxTask, (defRestartRunning | defInitContextRenew | defInitStatusCopyDo | defInitSharedActive | defInitStatusPrioKeep | defInitLockKeep | defInitProcessAll)); } } 01977 #endif 01978 /* When all tasks are shared the dominat mode makes no sense. */ 01979 #if ((includeTaskProtectSwitchTasks == cfgTrue) || (includeTaskProtectSwitchCritical == cfgTrue)) && (defAllSharedStack == cfgFalse) 01980 /* Only if the task has been 'done' we may switch to a new task. Otherwise, we are 01981 * still running this task. Note that all tasks are set to 'done' even before after start 01982 * so there must be a special situation when this has been changed to 'runnable'. Tasks that are 01983 * blocked, sleeping or cannot be continued in any way loose their switch block. Delayed tasks 01984 * may keep it, but the idle state will be called (technically this is not a switch). So first 01985 * test if we have indeed a state that does not block and is runnable*/ 01986 if ( (oldTCB->uiTaskStatus & (defBaseNoBlocksGetMask | defBaseDressGetMask)) == (defBaseNoBlocksTask | defBaseDressRunable) ) 01987 { /* If so, see if it is delayed */ 01988 if ((oldTCB->uiTaskStatus & defBaseDelayStateGetMask) == defBaseDelayStateDelayed) 01989 { /* delayed states go idle, and will persist to do so until the wake up. */ 01990 uiContextResult |= defAssignmentIdle; } } 01991 else 01992 #endif 01993 { /* After we have handle the shared tasks we must see if there are only shared tasks. In that case 01994 * we do not need to do an other selection, and know which task is selected, namely the only runable 01995 * one. */ 01996 #if (defAllSharedStack == cfgTrue) 01997 /* The task to be executed is the one selected by the shares. */ 01998 Tselect uiExecute = uiShareSelect; 01999 #else 02000 /* If there are also standard tasks, we must make a new selection about which task to run. */ 02001 Tselect uiExecute = privSelectTask(0x00,0,defNumberOfTasks); 02002 #endif 02003 if (uiExecute.MaxStatus == (defBaseRunningTask - 1)) 02004 { /* DISCUSSION 02005 * If we arrive here, all the tasks are terminated, suspended, sleeping, blocked or delayed. 02006 * (Thus, you cannot arrive here if there are running tasks, this is important for a correct 02007 * understanding of the decisions made below.) 02008 * The first situation can never recover, the next three cannot recover on their own, thus 02009 * the delayed tasks are their only hope. Thus we may go to sleep directly, or, when the 02010 * the minimum delay is long enough, for that time at least. Interrupts can revive 02011 * locked tasks may do so through the sleep anyway. Note that we disallowed sleep in case 02012 * of any write-file system activity or coming activity. 02013 * So see if we allow for low power sleep. If there are no tasks we cannot decide to go to sleep 02014 * by looking at the tasks. In fact, we should not sleep, maybe the idle loop has something 02015 * sensible to do, otherwise we just as well switch off the power. */ 02016 #if (cfgUseLowPowerSleep == cfgTrue) && (defNumberOfTasks > 0) 02017 Tuint08 uiLoopTask; 02018 /* Set the minimum delay to 255 block ticks, this is the largest value per default. */ 02019 Tuint08 uiMinDelay = defSleepMaximum; 02020 /* If there is any fs activity we do not need to test any further, so sort this out. If any 02021 * writing is going on, we may not fall asleep. Reading is permitted (read tasks cannot block 02022 * because of reading solely, only in combination of an other task writing or an other synchronization 02023 * primitive). Since we know there are no running tasks when arriving here, we only need to check 02024 * if there is not write block present.*/ 02025 #if (cfgUseFileSystem == cfgTrue) 02026 /* If the file system is in write block, there are tasks writing to the FS and we cannot put the 02027 * system into a sleep mode. If there is a read block, this is no problem by itself. 02028 * If we have a burn block, there must be a write block too, so we do not need to check 02029 * for burning separately.*/ 02030 if ((uiFsStatus & defFsWriteBlockGetMask) == defFsWriteBlockActive) 02031 { /* Setting uiLoopTask to zero blocks failing to sleep in the test below. */ 02032 uiLoopTask = 0; } 02033 else 02034 #endif 02035 { /* Now loop through all tasks to test if a sleep is justified. */ 02036 for (uiLoopTask=0; uiLoopTask<defNumberOfTasks; uiLoopTask++) 02037 { TtaskControlBlock * loopTCB = privTcbList(uiLoopTask); 02038 #if (cfgUseFileSystem == cfgTrue) 02039 /* Test first if we do not have a FS block, if so, no sleep. For we must first handle any 02040 * task that is waiting for an opportunity to start writing. Task blocking for reading 02041 * operations should not hinder falling asleep. However, there cannot be a situation where 02042 * all tasks are solely blocked on reading. One read block implies an other task blocked 02043 * on writing. And even if that where possible we should not go to sleep since we cannot 02044 * store the blocked state. Tasks actually doing reading (but blocked or delayed) are 02045 * NOT FileBlocked, thus pass here undetected. When some tasks are actually writing 02046 * we never arrive here. End of the story is that any file block should hinder sleep. 02047 * The defBaseDressGetMask is not important. */ 02048 if ( (loopTCB->uiTaskStatus & defBaseFileBlockedGetMask) == defBaseFileBlockedTask ) { break; } 02049 #endif 02050 /* We can only arrive here if all tasks (until now) are terminated, suspended, sleeping of syncblocked. 02051 * (fs blocks are already filtered out). The task could be delayed or syncblocked, the latter with or 02052 * without delay. We cannot reach this place if there is any task that is able to run. 02053 * Here three situations are important. No delay, delay with UseLowPowerOnDelay or delay without UseLowPowerOnDelay. 02054 * First if delayed tasks are not possible then, there is nothing left to do. If we come here, this task 02055 * cannot hinder going to sleep anymore. 02056 * In the second situation, where we allow a sleep on (long) delays, we must determine the shortest delay among 02057 * all, where we only take tasks into account that will be reviving without the help from outside, i.e. 02058 * standard delayed tasks, or blocked delayed tasks (not on FS). 02059 * Third, if we do not allow a sleep on (long) delays, we must determine if we really do not have any delayed 02060 * tasks, thus check if there is a delay task, if so, we may not go to sleep. If there is no delayed 02061 * task, we could only arrive here (idle) if ALL tasks are stopped, suspended, sleeping of syncblocked. 02062 * Only an external event can revive any of them. We may go to sleep. 02063 * Note that it does matter if blocked state is delayed, since a delayed blocked state may revive 02064 * earlier, but only with help from an other task or from the outside. But it will certainly be revived 02065 * when its timer expires. We thus must treat is as if it is a normal delayed task. 02066 * It must however not be a stopped delayed task, since even if the timer expires it will never restart. */ 02067 #if (cfgUseDelay == cfgTrue) 02068 /* Test if we are in a delayed situation, that is not terminated or sleeping (fs is not possible any more) 02069 * but may be syncblocked. */ 02070 if ( (loopTCB->uiTaskStatus & (defBaseStopStateGetMask | defBaseModeGetMask | defBaseDelayStateGetMask)) == ( defBaseStopStateGo | defBaseModeSync | defBaseDelayStateDelayed ) ) 02071 #if (cfgUseLowPowerOnDelay == cfgTrue) 02072 { /* Second situation, we must determine the delay. We do not care for the low byte, this 256 ticks vanish in 02073 * the rounding. One tick block must at least be the delay. The calculation is correct, even if 02074 * loopTCB->uxDelay.HighByte < uxTickCount.HighByte do to the limited size of the type. */ 02075 Tuint08 uiDelayTime = loopTCB->uxDelay.HighByte - uxTickCount.HighByte; 02076 /* If the high bytes are equal, there will be no delay, in fact that task will be waked 02077 * [Is this possible at all, it seems not so, cause these tasks should have been waked earlier on ] 02078 * Delays as long as 0xFF00 or more are forbidden. */ 02079 if (uiDelayTime == 0 ) { break; } 02080 /* The time the device may be put to sleep is of course one tick block less otherwise, we could 02081 * be to late for the task to wake, thus we subtract one. */ 02082 uiDelayTime--; 02083 /* We have an option which specifies a lower bound on the sleep time. Sleep times below that 02084 * are not thought to be useful, thus if we find such a time, we might as well wait here */ 02085 if (uiDelayTime < defSleepThreshold ) { break; } 02086 /* We want to keep track of the smallest possible sleep time so far, cause that will be reported 02087 * to the portSleep method. */ 02088 if (uiMinDelay>uiDelayTime) { uiMinDelay = uiDelayTime; } } 02089 #else 02090 { /* Third situation, a present delay must prohibit going to sleep. */ 02091 break; } 02092 #endif 02093 #endif 02094 } 02095 } 02096 /* No we must see if we did not break out of the loop. If we did not ... */ 02097 if (uiLoopTask == defNumberOfTasks) 02098 { /* ... we indeed may go to sleep, the the caller so */ 02099 uiContextResult |= defAssignmentSleep; 02100 /* and let the portSleep method know what the longest possible sleep time is, for 02101 * which no tasks will be missed (note the you may sleep longer if you want). The highest 02102 * value that can emerge from a delay is 0xFE (from 0xFExx) so that we know that a value of 02103 * defSleepMaximum (0xFF) must mean that no delay was present at all. 02104 * Now we can use the subbyte to pass this information, since if we are going to sleep, the 02105 * information will be useless anyway. The tick counter can be corrected manually, but 02106 * we cannot expect it to be accurate up to the subtick */ 02107 uxTickCount.SubByte = uiMinDelay; } 02108 else 02109 #endif 02110 { /* If you arrive here, then or you did not allow for a sleep mode, or the conditions 02111 * to go go low power sleep are just not met. This implies running the idle task, 02112 * we are done, let the caller know. */ 02113 uiContextResult |= defAssignmentIdle; } } 02114 else 02115 { /* If you arrive here, then there is a task to be run. There are two possibilities. If all tasks 02116 * run in the shared mode, then there can only one task be active, so we do not need to select any 02117 * more, the only task must be the one, otherwise the task was selected in the selection process 02118 * thereafter. */ 02119 TtaskControlBlock * runTCB = privTcbList(uiExecute.MaxTask); 02120 /* So test if we only have shared tasks. */ 02121 #if (defAllSharedStack == cfgFalse) 02122 /* If not, it could be that all tasks in the current priority have already run, 02123 * so that we selected a task in the state defRunStateDone. If this is the case 02124 * then we know vice versa that all tasks in that priority have that state, 02125 * for otherwise it would have been selected due to the higher value of the status byte. */ 02126 if ((runTCB->uiTaskStatus & defBaseDressGetMask) == defBaseDressDone) 02127 { /* In fact we need only to restore the run state of the shared states of the current 02128 * priority. We do so if we have cfgUseHierarchicalRoundRobin activated, mostly however 02129 * it does not matter much, so we save the code. 02130 * However, we must take care that only running tasks are handled. 02131 * For the blocking tasks the dressbit is used for other purposes. This is all handled 02132 * within the function privMakeTasksRunable. */ 02133 #if (cfgUseHierarchicalRoundRobin == cfgTrue) 02134 privMakeTasksRunable(0x00,(runTCB->uiTaskStatus & defBasePrioGetMask),0,defNumberOfTasks,((cfgUseSynchronization == cfgSyncNon) && (cfgUseFileSystem == cfgFalse) && (defUseSharedStack == cfgFalse))); 02135 #else 02136 privMakeTasksRunable(0x00,0,defNumberOfTasks,((cfgUseSynchronization == cfgSyncNon) && (cfgUseFileSystem == cfgFalse) && (defUseSharedStack == cfgFalse))); 02137 #endif 02138 } 02139 #endif 02140 /* The state immediately needs to be set to the done state, to prohibit indefinite running, since, 02141 * when the dress bit is set this indicates a dominant mode. */ 02142 runTCB->uiTaskStatus = (runTCB->uiTaskStatus & defBaseDressSetMask) | defBaseDressDone; 02143 /* Having selected a new state to run, let us put in the status register. From 02144 * now on, that is the current task. */ 02145 uiOsStatus = (uiOsStatus & defTaskNumberSetMask) | (uiExecute.MaxTask << defOsTaskNumberShift); } } 02146 /* Tell the caller the result, which may be one of: defAssignmentIdle or defAssignmentSleep or 02147 * (and that was the default defAssignmentTask) */ 02148 return uiContextResult; } 02149 02150 02151 #if (cfgUseLowPowerSleep == cfgTrue) 02152 02153 static void privEnterSleep(Tuint08 uiTickMinDelay) 02154 { /* If you arrive here, you obviously wanted the device to go to sleep. 02155 * Here we make the last preparations before we can do so. 02156 * The OS stack is not relevant anymore, so to allow for maximal 02157 * depth on in the portSleep function, we want to reset it. This 02158 * however cannot be done with interrupts activated, since that 02159 * would open the possibility of an interrupt on an incomplete 02160 * stack. Thus the first thing to do is to deactivate the interrupts, 02161 * which is only necessary if they are active at all */ 02162 #if (cfgIntOsProtected == cfgFalse) 02163 /* We want timer interrupts 02164 * disabled during sleep. The latter is the default situation, thus we do not 02165 * need to change anything to the tick interrupts. 02166 * If we come here, global interrupts where enabled (no OS protection) thus 02167 * we must disable them explicitly. Timer interrupts where already disabled in 02168 * the privInitOs section, thus there is no need to repeat that. */ 02169 privDisableGlobalInterrupts(); 02170 #endif 02171 /* Let the system know we are about to enter the sleep mode, this information 02172 * is needed when we wakeup and restore the system state, since we always enter 02173 * the OS with privInitOS */ 02174 uiOsStatus = ((uiOsStatus & defContextSetMask) | defContextStateSleep); 02175 /* report we are going to bed */ 02176 privTrace(traceSleepStart); 02177 /* Now we may reset the stack, no fear for interrupts. */ 02178 privSetStack(&xOS.StackOS[OSstackInit]); 02179 /* Before we go to sleep, there may be some work to do, if a hook is installed */ 02180 #if (callAppEnterSleep == cfgTrue) 02181 appEnterSleep(); 02182 #endif 02183 /* If we wake from sleep, we want to be sure there is no SleepRequest left. We know that we could 02184 * never arrive here when we where writing, but it could be that the system is in read only mode. 02185 * This must be preserved. */ 02186 #if (cfgUseFileSystem == cfgTrue) 02187 uiFsStatus = (uiFsStatus & defFsSleepRequestSetMask) | defFsSleepRequestClear; 02188 #endif 02189 /* This is where it happens. Call (not jump to!) portSleep. This method 02190 * returns when the sleep is done. Note we enter the portSleep method with 02191 * global interrupts disabled, and we should return that way. In between the 02192 * interrupts may be enabled when needed. */ 02193 portSleep(uiTickMinDelay); 02194 /* After we have slept, there may be some work to do, if a hook is installed */ 02195 #if (callAppEnterSleep == cfgTrue) 02196 appExitSleep(); 02197 #endif 02198 /* If we return, make the jump here */ 02199 portJump(privTickYield); } 02200 02201 #endif 02202 02203 02204 static void privEnterIdle(void) 02205 { /* Arriving here, we want to put the device in idle mode. 02206 * Here we make the last preparations before we can do so. 02207 * The OS stack is not relevant anymore, so to allow for maximal 02208 * depth on in the portIdle function, we want to reset it. This 02209 * however cannot be done with interrupts activated, since that 02210 * would open the possibility of an interrupt on an incomplete 02211 * stack. Thus the first thing to do is to deactivate the interrupts, 02212 * which is only necessary if they are activated at all. 02213 * If we have OS protection, the interrupts are already off, and\ 02214 * the timer interrupts are permanently on. If not, we must take 02215 * care of that. */ 02216 #if (cfgIntOsProtected == cfgFalse) 02217 privDisableGlobalInterrupts(); 02218 #endif 02219 /* Timer interrupts are switch on (or must be on) in the idle mode 02220 * because we must return from idle due to a timer interrupt. 02221 * however, that is the responsibility of the portIdle implementation 02222 * Notify the OS that we enter the idle state now. This is needed at 02223 * return, cause we don't need to save any context then. */ 02224 uiOsStatus = ((uiOsStatus & defContextSetMask) | defContextStateIdle); 02225 /* Say that we are ready to start the idle task. */ 02226 privTrace(traceIdleStart); 02227 /* Reset the stack, so we maximal space in portIdle. */ 02228 privSetStack(&xOS.StackOS[OSstackInit]); 02229 /* Interrupts on of course, otherwise the timer interrupt cannot work, and 02230 * we are ready with the stack switch. */ 02231 privEnableGlobalInterrupts(); 02232 /* Before we enter the idle state the there may be some work to do */ 02233 #if (callAppEnterIdle == cfgTrue) 02234 appEnterIdle(); 02235 #endif 02236 /* Done, we goto (not call!) the portIdle. Thus, we do not return here. ;-) */ 02237 portJump(portIdle); } 02238 02239 02240 #if (defNumberOfTasks == 0) 02241 02242 /* Use an empty method test purposes if there are no tasks defined, we should never come here. */ 02243 static void privEnterTask(void) { while(true); } 02244 02245 #else 02246 02247 static void privEnterTask(void) 02248 { /* Arrive here when a task need to be executed. Here we make the last preparations before 02249 * we can do so. The OS stack must be changed to the task stack. This however cannot be 02250 * done with interrupts activated, since that would open the possibility of an interrupt 02251 * on an incomplete stack. Thus the first thing to do is to deactivate the interrupts, 02252 * which is only necessary if they are activated at all. 02253 * Timer interrupts are switch on (or must be on) in the task mode. This however is done 02254 * inside the portRestore method for its state is dependent on the previous interrupt 02255 * state of the task. Therefore, we keep (default situation) tick interrupts disabled 02256 * here. If we have OS protection, the interrupts are already off. If not, we must take 02257 * care of that. */ 02258 /* Notify the OS that we enter a task state now. This is needed at 02259 * return, cause we must save the context then. */ 02260 uiOsStatus = ((uiOsStatus & defContextSetMask) | defContextStateTask); 02261 /* Get the number of the task we are going to run (a call to privTaskNumber takes more bytes) */ 02262 Tuint08 uiTaskNumber = (uiOsStatus & defTaskNumberGetMask) >> defOsTaskNumberShift; 02263 /* Get the task control block of the current task also */ 02264 TtaskControlBlock * curTCB = privTcbList(uiTaskNumber); 02265 /* Say that we are ready to start the task, but we do this before we switch to the 02266 * task itself since we do not know if the privTrace action fits on the task stack. */ 02267 privTrace(traceTaskStart | uiTaskNumber); 02268 /* If we make use of register compression with constant registers, (remember the facility that saves 02269 * stack space by saving only those registers you use on the context), we must determine which 02270 * registers must be used. We need that information to calculate the space these will take 02271 * on the stack. */ 02272 #if (defRegisterUseConstant == cfgTrue) 02273 /* ... we can use the constant value */ 02274 Tuint08 uiRegisterUse = defRegisterUseCollect; 02275 #else 02276 /* otherwise we must extract it from flash. */ 02277 Tuint08 uiRegisterUse = portFlashReadStruc(TtaskDefinitionBlock,pxTDBlist[uiTaskNumber],Tuint16,uiRegisterUse); 02278 #endif 02279 /* We must determine the number of registers used by this task, in oder to calculate the 02280 * new stack level. Since that may require a function call, we perform that operation first.*/ 02281 #if (cfgCheckTaskStack == cfgTrue) 02282 #if (defRegisterUseConstant == cfgTrue) 02283 /* The constant defRegisterCount holds the number of registers used.*/ 02284 Tuint08 uiRegCount = defRegisterCount; 02285 #else 02286 /* We have to calculate the number dynamically */ 02287 Tuint08 uiRegCount = privRegisterCount(uiRegisterUse); 02288 #endif 02289 #endif 02290 /* Disable interrupts here, for interrupts make use of the stack, at least for the call. But this 02291 * is not allowed any more since we are about to fill the background variables.*/ 02292 #if (cfgIntOsProtected == cfgFalse) 02293 privDisableGlobalInterrupts(); 02294 #endif 02295 /* Make sure all calls are handled, for after this instruction we start filling the background 02296 * variables. The stack should not be used any more. I am not 100% sure this is sufficient, but 02297 * i think i have no other means at my disposal other than assembly, which we cannot use here. */ 02298 portBarrier(); 02299 /* If we make use of register compression with constant registers, we now fill the background 02300 * variable with the correct value. */ 02301 xOS.pxSave.uiRegisterUse = uiRegisterUse; 02302 /* If we check the use of registers we may not want to check all registers, even if they are used. Here we may 02303 * want to check for all tasks the same registers so ...*/ 02304 #if (cfgCheckRegisters == cfgTrue) 02305 #if (defRegisterCheckConstant == cfgTrue) 02306 /* ... we can use the constant value */ 02307 xOS.pxSave.uiRegisterCheck = defRegisterCheckCollect; 02308 #else 02309 /* otherwise we must extract it from flash. */ 02310 xOS.pxSave.uiRegisterCheck = portFlashReadStruc(TtaskDefinitionBlock,pxTDBlist[uiTaskNumber],Tuint16,uiRegisterCheck); 02311 #endif 02312 #elif (cfgCheckWatermarks == cfgTrue) 02313 /* If we collect watermarks and do not check the registers, we want to collect this 02314 * information from all registers, thus */ 02315 xOS.pxSave.uiRegisterCheck = (registersAll); 02316 #endif 02317 /* If we do some checks on the use of the task stack (which are done on portSaveContext) 02318 * we prepare that information here, and put it in the background variables */ 02319 #if (cfgCheckTaskStack == cfgTrue) || (cfgCheckWatermarks == cfgTrue) 02320 /* Stack size is needed on two occasions */ 02321 #if (defStackSizeConstant == cfgTrue) 02322 Tstack uiStackSize = defStackSizeFixed; 02323 #else 02324 Tstack uiStackSize = portFlashReadStruc(TtaskDefinitionBlock,pxTDBlist[uiTaskNumber],Tstack,uiStackSize); 02325 #endif 02326 #endif 02327 /* At saveContext we need to know where the stack starts, but since getting this info 02328 * may overflow the stack at that time, we get it here and save it on the OS stack which 02329 * is used as background storage for the task. */ 02330 xOS.pxSave.pcStackOffset = portFlashReadStruc(TtaskDefinitionBlock,pxTDBlist[uiTaskNumber],Taddress,pcStackOffset); 02331 /* Some methods return a boolean to the application code. This data is put in the 02332 * correct register by the restoreContext. At this point we prepare it */ 02333 #if (cfgUseSynchronization != cfgSyncNon) && (defUseBoolReturns == cfgTrue) 02334 /* Put that information in the background variables */ 02335 xOS.pxSave.uiReturn = curTCB->defRetField & defRetGetMask ; 02336 #endif 02337 #if (cfgCheckTaskStack == cfgTrue) 02338 /* Calculate the limit for the stack size. We do that calculation also here, so that, 02339 * in the portSaveContext, we can do a simple compare. */ 02340 #if (cfgSysStackGrowthUp == cfgTrue) 02341 /* TODO: cfgSysStackGrowthUp oops, add code */ 02342 xOS.pxSave.pcStackLimit = 0; 02343 #else 02344 /* Note that the limit is calculated taking StackSavety into account. Thus, it is an error 02345 * to pass this limit, although the stack is not yet corrupted at that point. This is 02346 * intentional, so that we can stop the task rather than experiencing bizarre results, 02347 * when experimenting with the stack size. The +1 represents the status register.*/ 02348 xOS.pxSave.pcStackLimit = uiRegCount+xOS.pxSave.pcStackOffset+StackSafety-uiStackSize+1; 02349 #endif 02350 #endif 02351 /* Here we will scan the stack for bytes that differ from the initial bye. This indicates the use of 02352 * the stack also on places where no interrupt is possible (at the context the stack is used heavily, 02353 * but it may not give the absolute top if tick interrupts are disabled during deep calls. */ 02354 #if (cfgCheckWatermarks == cfgTrue) 02355 #if (cfgSysStackGrowthUp == cfgTrue) 02356 /* I don't know, probably the offset point to the first writable byte*/ 02357 Taddress pStack = xOS.pxSave.pcStackOffset + uiStackSize - 1; 02358 /* We walk downwards */ 02359 while ( (*(pStack--) == defStackInitByte) && (uiStackSize--)); 02360 #else 02361 /* The watermark measurement starts from the top of the stack (first byte to be read), 02362 * which is below the stack offset */ 02363 Taddress pStack = xOS.pxSave.pcStackOffset - uiStackSize + 1; 02364 /* the stack is write, post decrement, thus, when we walk downwards, we must read, pre-increment. 02365 * We walk maximally the stack size downwards. If we encounter a value which differs from the 02366 * initial value, we can stop. */ 02367 while ( (*(pStack++) == defStackInitByte) && (uiStackSize--)); 02368 /* The level of bytes used is at least the number of bytes below the boundary found. 02369 * We assume the stack has not overflown, first it may produce erroneous results in 02370 * the calculation, and second, watermarking is a technique to detect how much stack space is 02371 * left, not to detect stack overflow.*/ 02372 #endif 02373 /* If we happen to find a higher level with this technique opposite to the level found 02374 * due to context save, there must have been a situation of heavy stack use inside a tick 02375 * protected region of the code. Good that we noticed it! */ 02376 if ((curTCB->uiStackMax)<(uiStackSize)) { curTCB->uiStackMax = uiStackSize; } 02377 #endif 02378 /* Recall the address stack level, and put it in the background variables. Thus this 02379 * variable gets accessible from the portSave/portContext routines. */ 02380 xOS.pxSave.pcStackLevel = (Taddress) &(curTCB->pcStackLevel); 02381 /* Now, switch to the task stack */ 02382 #if (cfgSysStackGrowthUp == cfgTrue) 02383 privSetStack( (Taddress) ((Tuint16) xOS.pxSave.pcStackOffset + (Tuint16) curTCB->pcStackLevel) ); 02384 #else 02385 privSetStack( (Taddress) ((Tuint16) xOS.pxSave.pcStackOffset - (Tuint16) curTCB->pcStackLevel) ); 02386 #endif 02387 /* We need not to activate the interrupts right here, since that is done in the 02388 * portRestoreContext at the end by the 'reti'. Jump to the routine that restores 02389 * the context for the task at hand. */ 02390 portJump(portRestoreContext); } 02391 02392 #endif 02393 02394 02395 #if (defUseDelay == cfgTrue) 02396 02397 static void privWakeupFromDelay(Tuint08 uiTaskNumber, TtaskControlBlock * taskTCB) 02398 { /* Call this if you want to wake up a task due to expiration of the delay timer. 02399 * That can be or a simple delay, or a task that has a time out on a block. 02400 * taskTCB must be the tcb that corresponds to the uiTaskNumber. */ 02401 #if ((cfgUseSynchronization != cfgSyncNon) || (cfgUseFileSystem == cfgTrue)) && (cfgUseTimeout == cfgTrue) 02402 /* If the task was in blocked state, it may be released for its timeout has passed. Note that 02403 * blocked tasks without a timeout are not delayed, so they never arrive here. The same holds for terminated 02404 * tasks, so unblocking a terminated task cannot result in a suspended task. Sleeping tasks may still be unblocked. 02405 * Resuming, this are the possibilities 02406 * (1) Terminated task: never delayed, should not arrive here. 02407 * (2) Suspended task: never blocked, cannot pass the test below. 02408 * (3) Sleeping, may be blocked, is always syncblocked, thus may timeout to free-sleeping 02409 * (4) FS block: may deblock to free, we must clear the FsFields 02410 * (5) Sync block: may deblock to free, we must clear the blocking slots 02411 * (6) Simple delay, just clear the delay. 02412 * (7) Shared task, may be scheduled for execution, just clear the delay 02413 * */ 02414 if ((taskTCB->uiTaskStatus & defBaseBlockStateGetMask) == defBaseBlockStateBlocked) 02415 { /* We can savely assume we only enter this part of the code if the present task indeed 02416 * has a slotstack. If not, the task could never be blocked. so we dont check. Since 02417 * privRestoreInitialPriority and privUnblockTask assume such uiTaskSlot is present, 02418 * they may crash if the fields do not exist. */ 02419 /* If we have priority lifting .. */ 02420 #if (cfgUseSynchronization != cfgSyncNon) && (cfgUsePriorityLifting == cfgTrue) 02421 /* ... and if we release, its priority may be changed (we don't know for sure) in any case 02422 * it must be restored. For the moment however we only support priority lifting on sync blocked 02423 * tasks. Thus we must test if we indeed have syncblocking. We included sleeping in this task 02424 * for all sleeping tasks must come from syncblocks.*/ 02425 if ((taskTCB->uiTaskStatus & (defBaseModeGetMask | defBaseDressGetMask)) == (defBaseModeSync | defBaseDressSlot)) 02426 { privRestoreInitialPriority(uiTaskNumber); } 02427 #endif 02428 /* Release the task by unblocking and unlocking and indicate that it was release by a timeout 02429 * so the requested lock was not obtained (return false) There is no need to check if other 02430 * tasks must be released since we remove a blocking task, which cannot have consequences 02431 * for other blocked/waiting tasks.*/ 02432 privUnblockTask(uiTaskNumber | defParaLockStateUnlock | defParaRetStateFalse); } 02433 /* The unblocking above also wakes the task so we may skip it here. */ 02434 else 02435 #endif 02436 /* wake the task */ 02437 { taskTCB->uiTaskStatus = (taskTCB->uiTaskStatus & defBaseDelayStateSetMask) | defBaseDelayStateWake; } } 02438 02439 #endif 02440 02441 02442 #if (cfgUseLoadMonitor == cfgTrue) 02443 02444 static void privCopyLoad(void) 02445 { /* Arrive here if we want to monitor the load of all tasks, the Os and the Isr. Every now 02446 * and then we copy the collected subticks to the totals and clear the collectors. Since 02447 * this routine is not interrupted, we get an adequate picture of the loads. */ 02448 #if (cfgCheckTrace == cfgTrue) 02449 /* If we have tracing, first sent to the trace channel load info is comming */ 02450 privTrace(traceLoadInfo); 02451 /* then send the number of bytes to follow. */ 02452 privTrace(2*(defNumberOfTasks+3)); 02453 #endif 02454 /* Copy the OS load information into the register total. */ 02455 uiOsLoadTotal = uiOsLoadCollect; 02456 #if (cfgCheckTrace == cfgTrue) 02457 /* Send the load of the OS in big endian. */ 02458 privTrace((Tbyte)(uiOsLoadTotal>>8)); 02459 privTrace((Tbyte)(uiOsLoadTotal)); 02460 #endif 02461 /* Reset the collecting register. */ 02462 uiOsLoadCollect = 0; 02463 /* Copy the idle load information into the register total. */ 02464 uiIdleLoadTotal = uiIdleLoadCollect; 02465 #if (cfgCheckTrace == cfgTrue) 02466 /* Send the load of the idle 'task' in big endian. */ 02467 privTrace((Tbyte)(uiIdleLoadTotal>>8)); 02468 privTrace((Tbyte)(uiIdleLoadTotal)); 02469 #endif 02470 /* Reset the collecting register. */ 02471 uiIdleLoadCollect = 0; 02472 /* Only if non empty interrupts we need to copy the isr load. Otherwise, these variables 02473 * are absent. */ 02474 #if (cfgIntUserDefined == cfgTrue) 02475 /* Copy the ISR load information into the register total. */ 02476 uiIsrLoadTotal = uiIsrLoadCollect; 02477 #if (cfgCheckTrace == cfgTrue) 02478 /* Send the load of the ISR in big endian. */ 02479 privTrace((Tbyte)(uiIsrLoadTotal>>8)); 02480 privTrace((Tbyte)(uiIsrLoadTotal)); 02481 #endif 02482 /* Reset the collecting register. */ 02483 uiIsrLoadCollect = 0; 02484 #else 02485 #if (cfgCheckTrace == cfgTrue) 02486 /* We even send if we have no ISR whatsoever, since we want to emit a fixed number of bytes.*/ 02487 privTrace(0); 02488 privTrace(0); 02489 #endif 02490 #endif 02491 /* Depending on the number of tasks, we move the loads, and send the info. */ 02492 Tuint08 uiLoopTask; 02493 for (uiLoopTask=0; uiLoopTask<defNumberOfTasks; uiLoopTask++) 02494 { TtaskControlBlock * loopTCB = privTcbList(uiLoopTask); 02495 /* Copy the load information of this task into the register total. */ 02496 loopTCB->uiLoadTotal = loopTCB->uiLoadCollect; 02497 #if (cfgCheckTrace == cfgTrue) 02498 /* Send the load of the task in big endian. */ 02499 privTrace((Tbyte)(loopTCB->uiLoadTotal>>8)); 02500 privTrace((Tbyte)(loopTCB->uiLoadTotal)); 02501 #endif 02502 /* Reset the collecting register. */ 02503 loopTCB->uiLoadCollect = 0; } } 02504 02505 #endif 02506 02507 02508 #if (cfgCheckWatermarks == cfgTrue) && (cfgCheckTrace == cfgTrue) 02509 02510 static void privTraceWatermarks(void) 02511 { /* Arrive here too send the water mark and register use information to tracing. 02512 * First send the byte indicating that Watermarks are coming, then send the 02513 * number of bytes to follow. */ 02514 privTrace(traceWatermarks); 02515 privTrace(3*defNumberOfTasks+3); 02516 /* Send the watermark info of the OS. */ 02517 privTrace(uiOsStackMax); 02518 /* See if we are using an isr */ 02519 #if (defUseIsrStack == cfgTrue) 02520 /* Send the watermark of the isr stack, and depending on the size we must send 02521 * an extra zero. */ 02522 #if ((StackSizeISR) > 0xFF) 02523 privTrace((Tbyte)(uiIsrStackMax>>8)); 02524 #else 02525 privTrace(0); 02526 #endif 02527 privTrace((Tbyte)(uiIsrStackMax)); 02528 #else 02529 /* If not send zero's */ 02530 privTrace(0); 02531 privTrace(0); 02532 #endif 02533 /* Depending on the number of tasks, we move the loads. */ 02534 Tuint08 uiLoopTask; 02535 for (uiLoopTask=0; uiLoopTask<defNumberOfTasks; uiLoopTask++) 02536 { TtaskControlBlock * loopTCB = privTcbList(uiLoopTask); 02537 /* Depending on the size of the Stack we must send a zero byte or extract the first byte */ 02538 #if (defStackSizeExceedsOneByte == cfgTrue) 02539 privTrace((Tbyte)(loopTCB->uiStackMax>>8)); 02540 #else 02541 privTrace(0); 02542 #endif 02543 privTrace((Tbyte)(loopTCB->uiStackMax)); 02544 /* Send the use of the registers. */ 02545 privTrace((Tbyte)(loopTCB->uiRegisterUse)); } } 02546 02547 #endif 02548 02549 02550 #if (defUseDelay == cfgTrue) 02551 02552 #if (includeTaskDelayFromWake == cfgTrue) 02553 static void privDelayCalc(Tuint16 uiDelayTime, Tbool bFromNow) 02554 #else 02555 static void privDelayCalcFromNow(Tuint16 uiDelayTime) 02556 #endif 02557 { /* This is the delay core code. Several routines make use of it. Arrive here if you need to 02558 * to set the delay variables of the task control block. */ 02559 #if (cfgCheckOsStack == cfgTrue) || (cfgCheckWatermarks == cfgTrue) 02560 /* This is one of the places in the current design of the Femto OS that is somewhat deeper. 02561 * Thus it makes sense to check the OS stack here. */ 02562 privCheckOsStackLevel(); 02563 #endif 02564 TtaskControlBlock * curTCB = privTcbList(privTaskNumber(defCurrentTaskNumber)); 02565 /* There are two different forms of delay. The time measured form the current value of the 02566 * tick counter or from the last value of activation. The latter is stored in the delay 02567 * variables. If we have no need for DelayFromWake we exclude the section. */ 02568 #if (includeTaskDelayFromWake == cfgTrue) 02569 if (bFromNow) 02570 #else 02571 if (true) 02572 #endif 02573 { /* Here the new time is calculated form the current time. */ 02574 /* Now calculate the new Delaytime. This is a 16 bit operation. Note that the uiDelaytime 02575 * parameter represents the requested delay time whereas the uiDelayTime field in the 02576 * task control block represents the wakeup time of the particular task due to delay. */ 02577 uiDelayTime += uxTickCount.Full; } 02578 else 02579 { /* Here the new time is calculated from the last wake time. */ 02580 #if (cfgCheckTiming == cfgTrue) 02581 /* We can assume we do not want to set a new wake time that is in he past, although it 02582 * is not an error in absolute sense. However, we no code that protects in this case 02583 * it being interpreted as a long delay. Therefore we report an error. */ 02584 Tuint16 uiMinDelay = (uxTickCount.Full - curTCB->uxDelay.Full) ; 02585 if (uiDelayTime < uiMinDelay) 02586 /* Unfortunately we do not know which method called the function, so we cannot issue the 02587 * correct callID with certainty. Since the method declaration is already complicated enough 02588 * we issue a IdSystem error here. We do know however that it must be the current task 02589 * causing the problems, and that we are in pseuso task-space, thus we may switch at error. */ 02590 { privShowError((errTaskDelayTooShort | errTaskStateCurrent | errOsStateAsIs), callIdSystem, errCurrentTask ); } 02591 #endif 02592 uiDelayTime += curTCB->uxDelay.Full; } 02593 /* We have a new wake time, so place it in the appropriate fields. */ 02594 curTCB->uxDelay.Full = uiDelayTime ; 02595 /* It may be that this task is in the near wake, in which all tasks are that are in the 02596 * same tick block as the current time. We must check this and set the near wake bit if 02597 * needed. */ 02598 if (curTCB->uxDelay.HighByte == uxTickCount.HighByte ) 02599 { uiOsStatus = ((uiOsStatus & defNearWakeStateSetMask) | defNearWakeStatePresent); } 02600 /* Update the task status of the task, say that the current task is delayed. If we want to 02601 * allow for delays below the minimum, we must add code here to check and keep the state 02602 * from being delayed. However we assume that this situation is normally not what you 02603 * want, because the task can be 'far behind'. We cannot get here for terminated tasks. */ 02604 curTCB->uiTaskStatus = (curTCB->uiTaskStatus & defBaseDelayStateSetMask) | defBaseDelayStateDelayed; } 02605 02606 #endif 02607 02608 02609 02610 #if (cfgUseSynchronization == cfgSyncSingleSlot) && ((cfgUseTaskWatchdog == cfgTrue) || ( includeTaskRecreate == cfgTrue )) 02611 02612 static void privCleanSlotStack(TtaskExtendedControlBlock * taskTCB) 02613 { taskTCB->uiTaskSlot = defSlotRightFree; } 02614 02615 #endif 02616 02617 02618 #if ((cfgUseSynchronization == cfgSyncSingleBlock) || (cfgUseSynchronization == cfgSyncDoubleBlock)) && ((cfgUseTaskWatchdog == cfgTrue) || ( includeTaskRecreate == cfgTrue )) 02619 02620 static void privCleanSlotStack(TtaskExtendedControlBlock * taskTCB) 02621 { Tuint08 * pTaskSlot = (Tuint08 *) &taskTCB->uiTaskSlot; 02622 /* We need to know the total size of the stack. Note that the number of 02623 * slots is the double of the depth. */ 02624 #if (defSlotDepthConstant == cfgTrue) 02625 /* It may be a constant and than we use that */ 02626 Tuint08 uiSDC = defSlotDepthCollect; 02627 #else 02628 /* Or it may be stored in flash*/ 02629 Tuint08 uiSDC = portFlashReadStruc(TtaskDefinitionBlock,pxTDBlist[uiControlTaskNumber & defTaskNumberGetMask],Tuint08,uiSlotDepth); 02630 #endif 02631 Tuint08 uiLoopSlot; 02632 for (uiLoopSlot=0; uiLoopSlot<uiSDC; uiLoopSlot++) { *pTaskSlot++ = defSlotFree; } } 02633 02634 #endif 02635 02636 #if (cfgUseSynchronization == cfgSyncSingleSlot) 02637 02638 static Tbool privOperateSlotStack(Tuint08 uiControlTaskNumber, Tuint08 uiSlotSlot) 02639 { /* Use this method to add remove one slot in the slot stack, or to search a slot. 02640 * This implementation can handle one slot only, and should be selected in case 02641 * you use only one slot and no nesting is required. The size is thus known. 02642 * The search is the default. The search can be decorated with search free only 02643 * or blocks only. Per default any match is valid. If we add a slot, it will always 02644 * be put at the first position. The slot that was at that position will be placed 02645 * elsewhere. This is to ensure that, if the task blocks, we know the blocking 02646 * slot is in the first position. */ 02647 TtaskExtendedControlBlock * taskTCB = (TtaskExtendedControlBlock *) privTcbList(uiControlTaskNumber & defTaskNumberGetMask); 02648 /* Just to be sure */ 02649 #if (cfgCheckOsStack == cfgTrue) || (cfgCheckWatermarks == cfgTrue) 02650 privCheckOsStackLevel(); 02651 #endif 02652 /* Now we must handle all cases separately. In one special case we want only to 02653 * clean the stack, it is easy, done below. The clean case is special. */ 02654 /* Load the value of the slot (left four bits are unused.) */ 02655 Tuint08 uiVal = taskTCB->uiTaskSlot; 02656 /* Searching to see if the slot stack is free of Mutexes and Queues is need only in the 02657 * case we must restore the priority after lifting. */ 02658 #if (cfgUsePriorityLifting == cfgTrue) 02659 /* We check if we want to see if the slot numbers representing Queues and Mutexes are absent */ 02660 if ((uiControlTaskNumber & defSlotOperateSQMMask) == defSlotOperateQMAbsent) 02661 { /* Test if slot represents a Queue or Mutex, if so return false, return true otherwise */ 02662 return ((uiVal < defNumberQueuBegin) || (uiVal >= defNumberMutexEnd)); } 02663 #endif 02664 /* We need the result of the equality of the requested slot and the stored slot more 02665 * often, so store this in a separate variable. Also, this is the default result value */ 02666 Tbool uiValIsSlot = (uiVal == uiSlotSlot); 02667 /* From this place on we will test the different situations. Please note that the default 02668 * result is return the value of uiValIsSlot. Thus if this is wat we want to return, we do 02669 * not need to do anything. */ 02670 /* Test if we were looking for free slots only */ 02671 if ((uiControlTaskNumber & defSlotOperateSFreeMask) == defSlotOperateSearchFree) 02672 { /* If we where, and the task was blocking, we must return false, since there 02673 * cannot be a matching slot. If the task was free we need to return the result 02674 * of uiValIsSlot, which is default. */ 02675 if ((taskTCB->uiTaskStatus & defSlotLoopBlockMask) == defSlotLoopBlockBlocked) return false; } 02676 /* Test if we want to add a slot */ 02677 if ((uiControlTaskNumber & defSlotOperateIncreaseMask) == defSlotOperateIncreaseAction) 02678 { /* If we make use of method checking, this slot should not be used at this moment */ 02679 #if (cfgCheckMethodUse == cfgTrue) 02680 /* Test if it is*/ 02681 if (uiVal != defSlotRightFree) 02682 /* If so return an error. Since we are potentially not stopping the current task, we want to return after the error. */ 02683 { privShowError((errSlotIncreaseFail | errTaskStateInfo | errOsStateForce), callIdSystem, ((uiSlotSlot << errInfoNumberShift) | ((uiControlTaskNumber & defTaskNumberGetMask) << errTaskNumberShift)) ); } 02684 #endif 02685 /* Report the locks */ 02686 #if (cfgCheckTrace == cfgTrue) 02687 /* First we report which task is currently running */ 02688 privTrace(traceSlotLock | (uiControlTaskNumber & defTaskNumberGetMask) ); 02689 /* Subsequently report the lock. */ 02690 privTrace(uiSlotSlot); 02691 #endif 02692 /* Set the new slot*/ 02693 taskTCB->uiTaskSlot = uiSlotSlot; 02694 /* and what we return is not of importance. */ } 02695 /* Test if we want to remove a slot */ 02696 if ((uiControlTaskNumber & defSlotOperateDecreaseMask) == defSlotOperateDecreaseAction) 02697 { /* Test if the slot matches. Now this is only needed if we make use of method checking, since it 02698 * is considered an error to remove a non existing slot. */ 02699 #if (cfgCheckMethodUse == cfgTrue) 02700 /* If it does not match */ 02701 if (!uiValIsSlot) 02702 /* report the error. Since we are potentially not stopping the current task, we want to return after the error. */ 02703 { privShowError((errSlotDecreaseFail | errTaskStateInfo | errOsStateForce), callIdSystem, ((uiSlotSlot << errInfoNumberShift) | ((uiControlTaskNumber & defTaskNumberGetMask) << errTaskNumberShift)) ); } 02704 #endif 02705 /* Report the unlocks */ 02706 #if (cfgCheckTrace == cfgTrue) 02707 /* First we report which task is currently running */ 02708 privTrace(traceSlotUnlock | (uiControlTaskNumber & defTaskNumberGetMask) ); 02709 /* Subsequently report the lock */ 02710 privTrace(uiSlotSlot); 02711 #endif 02712 /* Remove the slot, even if it does not match, cause we may asume it does. */ 02713 { taskTCB->uiTaskSlot = defSlotRightFree; } 02714 /* We return with false, since this condition may only return true if an other slot of the same number 02715 * is present on the stack. This cannot be the case however, since there is only one slot present. */ 02716 return false; } 02717 /* In all remaining cases we where just searching, and since there is only one slot a simple test is enough. */ 02718 return uiValIsSlot; } 02719 02720 #endif 02721 02722 02723 #if (cfgUseSynchronization != cfgSyncNon) && (defUseQueus == cfgTrue) 02724 02725 static Tuint08 privGetQueuSize(Tuint08 uiQueuNumber) 02726 { /* Used to read the size of a particular queue from flash or to return the 02727 * constant if all sizes are equal. */ 02728 Tuint08 uiResult; 02729 /* So first determine if they are equal */ 02730 #if (defQueuSizeConstant == cfgTrue) 02731 /* Fixed sizes, return the constant. */ 02732 uiResult = defQueuSizeFixed; 02733 #else 02734 /* Otherwise we must look it up from a table in flash. */ 02735 uiResult = portFlashReadWord(Tuint08,uiQueuSize[uiQueuNumber]); 02736 #endif 02737 /* Done, return the size of the queue. */ 02738 return uiResult; } 02739 02740 #endif 02741 02742 02743 02744 #if (cfgUseSynchronization == cfgSyncSingleBlock) || (cfgUseSynchronization == cfgSyncDoubleBlock) 02745 02746 static Tbool privOperateSlotStack(Tuint08 uiControlTaskNumber, Tuint08 uiSlotSlot) 02747 { /* Use this method to add remove slots in the slot stack, or to search a slot. 02748 * The latter is the default. The search can be decorated with search free only 02749 * or blocks only. Per default any match is valid. If we add a slot, it will always 02750 * be put at the first position. The slot that was at that position will be placed 02751 * elsewhere. This is to ensure that, if the task blocks, we know the blocking 02752 * slot is in the first position. Two slots can be added simultaneously, they always 02753 * take the first bytes. */ 02754 /* The default reaction is false, but this is only needed if we have double slots, since 02755 * then it is sometimes handy to have a default reaction. Normally you should not enter 02756 * this method with the free slot. */ 02757 TtaskExtendedControlBlock * taskTCB = (TtaskExtendedControlBlock *) privTcbList(uiControlTaskNumber & defTaskNumberGetMask); 02758 /* Just to be sure */ 02759 #if (cfgCheckOsStack == cfgTrue) || (cfgCheckWatermarks == cfgTrue) 02760 privCheckOsStackLevel(); 02761 #endif 02762 /* pTaskSlot holds the pointer to the first two slots in the stack. The rest 02763 * of the stack is outside the TaskControlBlock. */ 02764 Tuint08 * pTaskSlot = (Tuint08 *) &taskTCB->uiTaskSlot; 02765 /* We need to know the total size of the stack. Note that the number of 02766 * slots is the double of the depth. */ 02767 #if (defSlotDepthConstant == cfgTrue) 02768 /* It may be a constant and than we use that */ 02769 Tuint08 uiSDC = defSlotDepthCollect; 02770 #else 02771 /* Or it may be stored in flash*/ 02772 Tuint08 uiSDC = portFlashReadStruc(TtaskDefinitionBlock,pxTDBlist[uiControlTaskNumber & defTaskNumberGetMask],Tuint08,uiSlotDepth); 02773 #endif 02774 Tuint08 uiLoopSlot; 02775 /* This variable is needed to hold some slots later on. */ 02776 Tuint08 uiVal; 02777 /* Searching to see if the slotstack is free of Mutexes and Queues is need only in the 02778 * case we must restore the priority after lifting. */ 02779 #if (cfgUsePriorityLifting == cfgTrue) 02780 /* We check if we want to see if the slot numbers representing Queues and Mutexes are absent */ 02781 if ((uiControlTaskNumber & defSlotOperateSQMMask) == defSlotOperateQMAbsent) 02782 { /* Loop through all the slots */ 02783 for (uiLoopSlot=0; uiLoopSlot<uiSDC; uiLoopSlot++) 02784 { /* Get the first to slots (technically the left slot in the zeroth slot can never be 02785 * a wait, but checking does not harm either.*/ 02786 uiVal = *pTaskSlot++; 02787 /* Extract the left slot */ 02788 Tuint08 uiLeftSlot = (uiVal & defSlotLeftGetMask) >> defSlotLeftShift; 02789 /* Test if it represents a Queue or Mutex, if so return false */ 02790 if ((uiLeftSlot >= defNumberQueuBegin) && (uiLeftSlot < defNumberMutexEnd)) { return false;} 02791 /* Extract the right slot */ 02792 Tuint08 uiRightSlot = (uiVal & defSlotRightGetMask) >> defSlotRightShift; 02793 /* Test if it represents a Queue or Mutex, if so return false */ 02794 if ((uiRightSlot >= defNumberQueuBegin) && (uiRightSlot < defNumberMutexEnd)) { return false;} } 02795 /* If we did no encounter any Queues ore Mutexes, the stack is empty or contains only Waits, in that 02796 * case we may return true. */ 02797 return true; } 02798 #endif 02799 /* uiLoopControl will contains two bits of information. One to indicate that is 02800 * the task is free or blocked. And the second (set further below) to indicate if 02801 * the operation is to handle all slots. The latter is the default */ 02802 Tuint08 uiLoopControl = (taskTCB->uiTaskStatus & defSlotLoopBlockMask); 02803 /* If we are still here we did not search Waits only. Now if we are not searching 02804 * free slots only eigther or increase the stack (i.e. we search all or we decrease the stack, we must make 02805 * sure the loop below does not skip the first two slots in the search loop below. so override 02806 * the blocked state form the task to enforce checking the first byte. */ 02807 if (((uiControlTaskNumber & defSlotOperateSFreeMask) != defSlotOperateSearchFree) && ((uiControlTaskNumber & defSlotOperateIncreaseMask) != defSlotOperateIncreaseAction)) 02808 { uiLoopControl = defSlotLoopBlockNon; } 02809 /* The loop below contains two parts, a test for each slot position and an action. The default 02810 * is to test agains the given slot, and to replace the found value with the freeSlot (0x00) 02811 * Since searching can only be at one slot at a time, we know uiSlotSlot has first four bits zero */ 02812 Tuint08 uiTest = uiSlotSlot; 02813 Tuint08 uiFill = defSlotRightFree; 02814 /* Load the value of the fist two slots. */ 02815 uiVal = *pTaskSlot; 02816 /* However in case we want to add a slot, we must look for a free slot and substitute the 02817 * value that was placed first, which in his turn must contain the new value. Thus */ 02818 if ((uiControlTaskNumber & defSlotOperateIncreaseMask) == defSlotOperateIncreaseAction) 02819 {/* Place the new slot at the first position, thereby leaving a possible second position in tact */ 02820 #if (cfgUseSynchronization == cfgSyncDoubleBlock) 02821 /* In this case the whole byte is reserved for the new lock, which may contain two slots. */ 02822 *pTaskSlot = uiSlotSlot; 02823 #else 02824 /* In this case the left nibble can contain a free lock which must be preserved, and uiSlotSlot can only 02825 * contain one slot */ 02826 *pTaskSlot = (uiVal & defSlotRightSetMask) | uiSlotSlot; 02827 #endif 02828 /* Report the locks */ 02829 #if (cfgCheckTrace == cfgTrue) 02830 /* First we report which task is currently running */ 02831 privTrace(traceSlotLock | (uiControlTaskNumber & defTaskNumberGetMask) ); 02832 /* Report the slots */ 02833 privTrace(uiSlotSlot); 02834 #endif 02835 /* and from now on we look for empty slots */ 02836 uiTest = defSlotRightFree; 02837 /* Which must be filled with the value that was on the first place before. */ 02838 #if (cfgUseSynchronization == cfgSyncDoubleBlock) 02839 /* For a double block both slots may need replacement */ 02840 uiFill = uiVal; 02841 #else 02842 /* For a single block only the right nibble is interesting, the left may contain a free lock */ 02843 uiFill = (uiVal & defSlotRightGetMask); 02844 #endif 02845 /* If that slot was empty before, it makes no sense to continue (although it cannot harm) 02846 * and we are done. */ 02847 if (uiFill == defSlotFree) return false; 02848 /* If we do continue we may not test the first nibble/byte since that is what we just filled, and we do 02849 * not want to risk a double block. so we simulate a block. */ 02850 uiLoopControl = defSlotLoopBlockBlocked; } 02851 /* If we do not want to add a slot, we are about to remove one, or search for one. In case 02852 * we do not want to remove one, we search for one, and indicate so in the uiLoopControl variable. 02853 * This is to make sure we leave when found, before we substitute a value. */ 02854 else if ((uiControlTaskNumber & defSlotOperateDecreaseMask) != defSlotOperateDecreaseAction) 02855 { uiLoopControl |= defSlotLoopSearchActive; } 02856 /* If we are decreasing, maybe we must inform the outside world we are doing so */ 02857 #if (cfgCheckTrace == cfgTrue) 02858 else 02859 { /* Here we are decreasing, which we want to report the unlocks, first we report which task is currently running */ 02860 privTrace(traceSlotUnlock | (uiControlTaskNumber & defTaskNumberGetMask) ); 02861 /* Report the slot(s) */ 02862 privTrace(uiSlotSlot); } 02863 #endif 02864 /* Start looping at the beginning or skip the first byte depending on the situation of the uiLoopControl. */ 02865 if ((uiLoopControl & defSlotLoopBlockMask) == defSlotLoopBlockNon) 02866 { uiLoopSlot = 0; } 02867 else 02868 { /* We must distinguish the double and single block situations */ 02869 #if (cfgUseSynchronization == cfgSyncDoubleBlock) 02870 /* In this case we need to skip the first full byte, which contains the new slots */ 02871 uiLoopSlot = 2; 02872 pTaskSlot++; 02873 #else 02874 /* In this case we need to skip only the first nibble, which contains the new slot */ 02875 uiLoopSlot = 1; 02876 #endif 02877 } 02878 /* Now run through all slots, double the number because we check left and right nibble with the same code */ 02879 while (uiLoopSlot<2*uiSDC) 02880 { uiVal = *pTaskSlot; 02881 /* At odd passes we check the other nibble (slot) */ 02882 if ((uiLoopSlot & 0x01) == 0x01) { portSwapNibbles(uiVal); } 02883 /* Test if the right slot fulfills the test, and if so, test also if we may test this slot. The latter may 02884 * not be the case for the very first slot, when we are only searching for free slots and this task is blocking. */ 02885 if ((uiVal & defSlotRightGetMask) == uiTest ) 02886 { /* So we found a match on the right slot. If we were only searching, we may leave with the message we found a hit. */ 02887 if ((uiLoopControl & defSlotLoopSearchMask) == defSlotLoopSearchActive) return true; 02888 /* If we were replacing (for increase or decrease), do so now */ 02889 #if (cfgUseSynchronization == cfgSyncDoubleBlock) 02890 /* We simply slide in the new value on the right, if the values ware swapped before 02891 * that does not matter */ 02892 *pTaskSlot = (uiVal & defSlotRightSetMask) | (uiFill & defSlotRightGetMask); 02893 #else 02894 /* Calculate the new value for the slot stack */ 02895 Tuint08 uiNewVal = (uiVal & defSlotRightSetMask) | uiFill; 02896 /* here we must be careful since the sequence of nibbles on the bottom of the slot stack 02897 * does matter, so we must restore if we corrupted it */ 02898 if ((uiLoopSlot & 0x01) == 0x01) { portSwapNibbles(uiNewVal); } 02899 /* Now it is safe to store. */ 02900 *pTaskSlot = uiNewVal; 02901 #endif 02902 /* If we are decreasing, it is interesting to know if there is a second slot with the same number, 02903 * so we continue otherwise */ 02904 if ((uiControlTaskNumber & defSlotOperateIncreaseMask) == defSlotOperateIncreaseAction) 02905 { /* If there can be a second slot */ 02906 #if (cfgUseSynchronization == cfgSyncDoubleBlock) 02907 /* We move to the second slot */ 02908 uiFill >>= 4; 02909 /* there may be no second slot to paste */ 02910 if (uiFill == defSlotFree) { return false; } 02911 #else 02912 /* If not we are done, the return value is of no importance */ 02913 return false; 02914 #endif 02915 } 02916 else 02917 { /* we are decreasing, so turn the operation into a search */ 02918 uiLoopControl |= defSlotLoopSearchActive; } } 02919 /* Only at odd passes we check go to the next byte in the stack */ 02920 if ((uiLoopSlot & 0x01) == 0x01) { pTaskSlot++; } 02921 uiLoopSlot++; } 02922 /* If we found nothing, return false. If we were not searching but increasing we should not arrive here, 02923 * for it indicates we could not add the slot. If we where decreasing arriving here means the there was no 02924 * slot with the given number that could be removed. If this is an error depends on the caller. */ 02925 #if (cfgCheckMethodUse == cfgTrue) 02926 /* Test if we arrived here while increasing, if so we could not add the slot for the stack is full. 02927 * Since we are potentially not stopping the current task, we want to return after the error. */ 02928 if ((uiControlTaskNumber & defSlotOperateIncreaseMask) == defSlotOperateIncreaseAction) 02929 { privShowError((errSlotIncreaseFail | errTaskStateInfo | errOsStateForce), callIdSystem, ((uiSlotSlot << errInfoNumberShift) | ((uiControlTaskNumber & defTaskNumberGetMask) << errTaskNumberShift)) ); } 02930 /* Test if we arrived here while decreasing and did not yet succeed in doing so. If so the slot 02931 * was not present and this is considered an error. If we where decreasing and searching, we did 02932 * not find a second slot so we should return false, this is normal operation */ 02933 if ( ((uiControlTaskNumber & defSlotOperateDecreaseMask) == defSlotOperateDecreaseAction) && 02934 ((uiLoopControl & defSlotLoopSearchMask) != defSlotLoopSearchActive) ) 02935 { /* Since we are potentially not stopping the current task, we want to return after the error. */ 02936 privShowError((errSlotDecreaseFail | errTaskStateInfo | errOsStateForce), callIdSystem, ((uiSlotSlot << errInfoNumberShift) | ((uiControlTaskNumber & defTaskNumberGetMask) << errTaskNumberShift)) ); } 02937 #endif 02938 return false; } 02939 02940 #endif 02941 02942 #if (cfgUseSynchronization != cfgSyncNon) && ((defUseMutexes == cfgTrue) || (defUseQueus == cfgTrue)) 02943 02944 static Tuint08 privFreeLockAbsent(Tuint08 uiSlot) 02945 { /* This method is used to see if a particular slot is occupied by an other task as a free lock. 02946 * Thus it returns true when the slot is totally unused, returns true when it is only used 02947 * as blocking slots or if you call it with the free Slot. Note that it returns false if the 02948 * slot has been used in a task as free, even if that task was later blocked. */ 02949 /* Just to be sure */ 02950 #if (cfgCheckOsStack == cfgTrue) || (cfgCheckWatermarks == cfgTrue) 02951 privCheckOsStackLevel(); 02952 #endif 02953 if (uiSlot != defSlotFree) 02954 { Tuint08 uiLoopTask; 02955 /* Run trough all tasks that use slots */ 02956 for (uiLoopTask=0; uiLoopTask<defNumberOfTasksWithSlot; uiLoopTask++) 02957 { /* Search for the use of this slots as free slots in de the slotstack. privOperateSlotStack returns 02958 * true if the slot is reported free in this task. If so we may stop here, if not we must continue 02959 * to search. */ 02960 if ( privOperateSlotStack((uiLoopTask | defSlotOperateSearchFree ), uiSlot ) ) { return false; } } } 02961 /* If we have not found any free use of the slot, the slot is not used as such. */ 02962 return true; } 02963 02964 #endif 02965 02966 02967 #if (cfgUseSynchronization != cfgSyncNon) || (cfgUseFileSystem == cfgTrue) || (cfgUseEvents == cfgTrue) 02968 02969 static void privUnblockTask(Tuint08 uiControlTaskNumber) 02970 { /* This method unlocks / unblocks a task for you, depending on the bits in uiControlTaskNumber. 02971 * It can handle fs blocks and syncblocks. Only call this on blocking tasks, since it will 02972 * always perform a deblock, there is no test if the task is indeed blocked. Terminated and 02973 * suspended tasks are ignored. It may NOT be called on shared tasks. */ 02974 TtaskExtendedControlBlock * taskTCB = (TtaskExtendedControlBlock *) privTcbList(uiControlTaskNumber & defTaskNumberGetMask); 02975 /* Just to be sure */ 02976 #if (cfgCheckOsStack == cfgTrue) || (cfgCheckWatermarks == cfgTrue) 02977 privCheckOsStackLevel(); 02978 #endif 02979 /* Check if the task is not terminated or suspended, since they may not be unlocked, for all the 02980 * other types (sleeping included) there is no problem */ 02981 if (taskTCB->uiTaskStatus >= defBaseSleepingTask) 02982 { /* First we see if the caller wanted to unlock the task too. */ 02983 if ((uiControlTaskNumber & defParaLockMask) == defParaLockStateUnlock) 02984 { 02985 #if (cfgUseSynchronization != cfgSyncNon) 02986 if ((taskTCB->uiTaskStatus & defBaseModeGetMask) == defBaseModeSync) 02987 { /* If we make use of events, the test above also passes for event unlocks, thus we 02988 * must explicitly test in that case that we do not have an event unlock. This could 02989 * lead to the erasure of free slots. */ 02990 #if (cfgUseEvents == cfgTrue) 02991 if ((taskTCB->uiTaskStatus & defBaseDressGetMask) == defBaseDressSlot) 02992 #endif 02993 { /* Unlocking means setting the lowest slot number to zero, the 'free lock'. Note we assume that 02994 * slot is the correct one, for we came from a blocking situation. */ 02995 #if (cfgCheckTrace == cfgTrue) 02996 /* First we report which task is currently running */ 02997 privTrace(traceSlotUnlock | (uiControlTaskNumber & defTaskNumberGetMask) ); 02998 /* Report the slots */ 02999 privTrace(taskTCB->uiTaskSlot); 03000 #endif 03001 /* Clean the lock, depending on the type */ 03002 #if (cfgUseSynchronization == cfgSyncSingleSlot) 03003 /* We may clean all of it, since the left nibble is not used */ 03004 taskTCB->uiTaskSlot = defSlotFree; 03005 #elif (cfgUseSynchronization == cfgSyncSingleBlock) 03006 /* We must be careful for the left nibble may contain a free lock */ 03007 taskTCB->uiTaskSlot = (taskTCB->uiTaskSlot & defSlotRightSetMask) | defSlotRightFree; 03008 #elif (cfgUseSynchronization == cfgSyncDoubleBlock) 03009 /* We must be sure to clean all blocking slots. */ 03010 taskTCB->uiTaskSlot = defSlotFree; 03011 #else 03012 #error "You should not arrive here." 03013 #endif 03014 } } 03015 #endif 03016 #if (cfgUseFileSystem == cfgTrue) 03017 /* Check if the task is locked on the file system. (Note: shared tasks will pass this 03018 * test, therefore it may not be called on shared tasks.) */ 03019 if ((taskTCB->uiTaskStatus & defBaseModeGetMask) == defBaseModeAccess) 03020 { /* If so, we clean the read/write modes. Clean the locks, if present. Note we only do so 03021 * when requested to unlock. This is the case in for example when a delay occurs. */ 03022 #if (defUseFsField == cfgTrue) 03023 taskTCB->defFsField = (taskTCB->defFsField & (defFsReadSetMask & defFsWriteSetMask)) | (defFsReadClear | defFsWriteClear); 03024 #endif 03025 } 03026 #endif 03027 /* The last situation, namely, the Events, do not need standard unlocking operations, for we can 03028 * only arrive here if the uiTaskEvents has already be cleared. The only exception being in case 03029 * of timeouts. Also, there is no harm in cleaning the TaskEvent if we come from an unlock due 03030 * to a slot locking. Since if the task was blocking on a slot, it could not have been blocking on 03031 * an event to happen. In that case the TaskEvent variable should already be cleared. Thus */ 03032 #if (cfgUseEvents == cfgTrue) && (cfgUseTimeout == cfgTrue) 03033 taskTCB->uiTaskEvents = defAllEventsReset; 03034 #endif 03035 } 03036 privTrace(traceTaskRelease | (uiControlTaskNumber & defTaskNumberGetMask) ); 03037 /* ... if so, unblock the task and also remove a possible timeout. If we forget this, the task will 03038 * turn into a delayed state. This is needed since we also unblock tasks which are not the current ones. 03039 * A sleeping state may be deblocked and delay-waked, but must stay sleeping. Shared tasks are not allowed. */ 03040 taskTCB->uiTaskStatus = (taskTCB->uiTaskStatus & (defBaseModeSetMask & defBaseBlockStateSetMask & defBaseDelayStateSetMask & defBaseDressSetMask)) | (defBaseModeSync | defBaseBlockStateFree | defBaseDelayStateWake | defBaseDressDone); 03041 /* If we must return a value, this can only be the case after an unblock of course. Without an unblock, there 03042 * is no task to return something to. */ 03043 #if (defUseBoolReturns == cfgTrue) 03044 /* The return value is stored in the defRetField, and consists of two bits, one for true/false, one to 03045 * indicate if there is something to return. */ 03046 taskTCB->defRetField = (taskTCB->defRetField & defRetSetMask) | ((uiControlTaskNumber & defParaRetMask) >> defParaRetToRetShift); 03047 #endif 03048 /* If we want to keep track of accurate wake times, and we have release a task, we must copy the current 03049 * time to the delay fields, since this is the place where the time of last activation is kept.*/ 03050 #if (defUseDelay == cfgTrue) && (cfgUseCorrectWakeupTimes == cfgTrue) 03051 taskTCB->uxDelay.Full = uxTickCount.Full; 03052 #endif 03053 } } 03054 03055 #endif 03056 03057 03058 #if (cfgUseSynchronization != cfgSyncNon) && (cfgUsePriorityLifting == cfgTrue) 03059 03060 static void privLiftLocksOnSlot(Tuint08 uiSlot) 03061 { /* Arrive here when you need to increase the priorities of several tasks in a slot 03062 * of a task about to be blocked. By increasing those priorities to the level of 03063 * the blocking slot, these tasks have a chance to finish, and not keep the current 03064 * blocking task for ever. Note that we do not level all priorities in one slot, 03065 * since due to the fact that tasks may be blocked on two slots simultaneously this 03066 * would be a very costly to sort out. This mechanism tries to keep it simple.*/ 03067 TtaskControlBlock * curTCB = privTcbList(privTaskNumber(defCurrentTaskNumber)); 03068 /* Get the priority of the current task. Note we do not need to shift the 03069 * priority since we will only compare priorities among each other, we do not 03070 * need the exact value. */ 03071 Tuint08 uiCurTaskPriority = curTCB->uiTaskStatus & defBasePrioGetMask; 03072 Tuint08 uiLoopTask; 03073 TtaskControlBlock * loopTCB; 03074 /* Run through all task possible having a slot. */ 03075 for (uiLoopTask=0; uiLoopTask<defNumberOfTasksWithSlot; uiLoopTask++) 03076 { loopTCB = privTcbList(uiLoopTask); 03077 /* Test if the task indeed holds the slot. We do not distinguish between blocked and 03078 * locked only. Solely possessing the lock is enough to rise its priority. Sometimes 03079 * this may imply we rise tasks without a real need, but it would be to costly to 03080 * analyze on which slot the blocking takes place. */ 03081 if (privOperateSlotStack((uiLoopTask | defSlotOperateSearchDefault), uiSlot)) 03082 { /* Get the priority of the looped task, again, don't shift */ 03083 Tuint08 uiLoopTaskPriority = loopTCB->uiTaskStatus & defBasePrioGetMask; 03084 /* Compare which is larger */ 03085 if (uiCurTaskPriority>uiLoopTaskPriority) 03086 { /* and if the priotity of the current task (which will be blocked and thus inactivates 03087 * was larger, lift the priority of the other task to that of the current task. The 03088 * present priority gets lost. */ 03089 loopTCB->uiTaskStatus = (loopTCB->uiTaskStatus & defBasePrioSetMask) | uiCurTaskPriority; } } } } 03090 03091 #endif 03092 03093 03094 #if (cfgUseSynchronization != cfgSyncNon) && (cfgUsePriorityLifting == cfgTrue) 03095 03096 static void privRestoreInitialPriority(Tuint08 uiTaskNumber) 03097 { /* Arrive here if we need to restore the priority of a lifted task. The priority 03098 * is reset to the original value that is stored in flash. First we test if the 03099 * task does not hold any Queue's or Mutexes any more. */ 03100 if ( privOperateSlotStack((uiTaskNumber | defSlotOperateQMAbsent ), defSlotFree ) ) 03101 { /* If so it now makes sense to restore the priority. */ 03102 TtaskControlBlock * taskTCB = privTcbList(uiTaskNumber); 03103 /* Read the initial priority from flash, or use the constant */ 03104 #if (defInitialStatusConstant == cfgTrue) 03105 Tuint08 uiInitialStatus = defInitialStatusFixed; 03106 #else 03107 Tuint08 uiInitialStatus = portFlashReadStruc(TtaskDefinitionBlock,pxTDBlist[uiTaskNumber],Tuint08,uiInitialStatus); 03108 #endif 03109 /* Restore its value. */ 03110 taskTCB->uiTaskStatus = (taskTCB->uiTaskStatus & defBasePrioSetMask) | (uiInitialStatus & defBasePrioGetMask); } } 03111 03112 #endif 03113 03114 03115 #if (cfgUseSynchronization != cfgSyncNon) && (defUseQueus == cfgTrue) 03116 03117 /* The queue mechanism allows for several tasks writing and reading bytes. The OS 03118 * locks all tasks not able at that moment to write or read the required quantity of bytes. 03119 * Ah, and take care, the queues (and locks for that matter) are numbers from 1 and 03120 * onwards. Thus, slot 0 is forbidden, since it indicates a free slot. But queue's 03121 * are stored in arrays, thus slot 1 corresponds to queue 0 etc. Therefore you see 03122 * [uiSlot-1] everywhere. */ 03123 03124 /* DISCUSSION 03125 * Except in the beginning, the Read (pointer) and Write (pointer) are never equal. 03126 * This is because otherwise you could not see the difference between a 03127 * full and an empty queue. This would imply that one byte is effectively lost, 03128 * for it could never be retrieved. Such a waste! We must solve this 03129 * by storing one bit of information that differentiates between a full and an 03130 * empty queue, when Read and Write are equal. But where? 03131 * It seems reasonable to limit the size of queue's to 127 bytes. Now we have 03132 * two extra bits available (upper bits of Read/Write storage). Second advantage 03133 * is that we can address the whole queue, from the queue Requests. What we don't 03134 * know at this moment if this will cost a lot of code. 03135 * Now, we decided to reserve a bit to indicate that the queue is full, is 03136 * it handy to use the other for indicating an empty queue? Well, it may be, 03137 * but, since queue's are empty at startup, we want to indicate the bit 03138 * empty by zero. Hmmm, that implies a lot of code. It may be shorter to 03139 * just ask for Read==Write and !full. Ok let us see what happens. 03140 * Now we keep the write pointers in uiQueuWrite[] and the read pointers in 03141 * uiQueuRead[]. The write operation is write-post-decrement, and the read 03142 * operation likewise. The pointers wrap when they hit the bottom of the queue. 03143 * Thus we write/read downwards, the wrapping is easier detected that way. 03144 */ 03145 03146 03147 static Tuint08 privQueuTest(Tuint08 uiSlot, Tsint08 siFreeFilling) 03148 { /* If we want to know the size of a queue use this function, or if we 03149 * want to test if a certain number of bytes will fit. We use negative numbers 03150 * for writing, and positive numbers for reading. */ 03151 /* The size information of the queue is in flash, note the shift from slot numbers 03152 * to queue array numbering. */ 03153 Tuint08 uiSize = privGetQueuSize(uiSlot-1); 03154 /* Parameter FreeFilling zero is miss-used to request the size of the queue. */ 03155 if (siFreeFilling==0) { return uiSize; } 03156 /* The information about the write and read positions are stored in two arrays, the 03157 * uiQueuWrite and the uiQueuRead. Obtain the write pointer. That pointer points to 03158 * the location that has to be written. */ 03159 Tuint08 uiWrite = uiQueuWrite[uiSlot-1]; 03160 /* Extract the full bit. We assume it has been set and managed correctly, although it 03161 * only has a meaning when uiWrite==uiRead, for this is the only situation where we 03162 * have ambiguity. */ 03163 Tbool bFull = (uiWrite & defQueuFillingGetMask) == defQueuFillingStateFull; 03164 /* If the queue is full ... */ 03165 if (bFull) 03166 { if (siFreeFilling>0) 03167 { /* we can read as many bytes from the queue as it is long, */ 03168 return uiSize; } 03169 else 03170 { /* but we cannot write anything anymore to it. */ 03171 return 0; } } 03172 /* In other cases we must calculate the number, extract the read pointer. */ 03173 Tuint08 uiRead = uiQueuRead[uiSlot-1]; 03174 /* Now calculate how many readable characters there are. The situation that the queue 03175 * might be full was already resolved, so in the calculation below it is assumed the 03176 * queue is not full, i.e. uiWrite==uiRead implies it is empty. Make sure the calculation 03177 * never produced negative numbers. */ 03178 Tuint08 uiReadable = uiWrite<=uiRead ? uiRead - uiWrite : uiSize - (uiWrite - uiRead); 03179 /* Every byte that is not readable, must be writable. */ 03180 Tuint08 uiWriteable = uiSize - uiReadable; 03181 /* Now decide what to return, for positive siFreeFilling we asks for the readable characters, 03182 * for negative for the writable. */ 03183 if (siFreeFilling>0) 03184 { return uiReadable; } 03185 else 03186 { return uiWriteable; } } 03187 03188 #endif 03189 03190 03191 #if (cfgUseSynchronization != cfgSyncNon) && (defUseWaits == cfgTrue) 03192 03193 static void privReleaseWait(Tuint08 uiSlot) 03194 { /* This is called if we want to clean all locks in the tasks blocked by a wait. Cannot be 03195 * called to clean up Queues or Mutexes. */ 03196 Tuint08 uiLoopTask; 03197 /* Loop trough all tasks. */ 03198 for (uiLoopTask=0; uiLoopTask<defNumberOfTasksWithSlot; uiLoopTask++) 03199 { TtaskExtendedControlBlock * loopTCB = (TtaskExtendedControlBlock *) privTcbList(uiLoopTask); 03200 /* Check if the task holds a blocking slot with the given number. The slot can never be left, 03201 * since waits cannot be be blocked in pairs. Furthermore, the task must be blocking, wait slots 03202 * are never solely locked. */ 03203 if ((loopTCB->uiTaskSlot & defSlotRightGetMask) == uiSlot) 03204 { /* If the slot matches unblock and unlock the task */ 03205 privUnblockTask(uiLoopTask | defParaLockStateUnlock | defParaRetStateTrue); } } } 03206 03207 #endif 03208 03209 03210 #if (cfgUseSynchronization != cfgSyncNon) && (defUseQueus == cfgTrue) 03211 03212 static Tbool privSizeFitsQueu(Tuint08 uiSlot, Tsint08 siFreeFilling) 03213 { /* Call this if you need to test if a queue on a slot may fit the filling condition. First 03214 * test if we indeed have a queue, otherwise there is noting to test. */ 03215 if ((uiSlot >= defNumberQueuBegin) || (uiSlot < defNumberQueuEnd )) 03216 { Tuint08 uiTest; 03217 /* Now we test the siFreeFilling. This method returns the number of bytes that can read from / written to 03218 * the queue, depending on the sign of siFreeFilling. If siFreeFilling==0 it returns the queue size (which 03219 * value we do not need here) The number returned is always positive. */ 03220 uiTest = privQueuTest(uiSlot,siFreeFilling); 03221 /* If we want to read we may enter if we want to read not more bytes as are available */ 03222 if (siFreeFilling>0) { return ( ((Tuint08) siFreeFilling) <= uiTest); } 03223 /* If we want to read we may enter if we want to read not more bytes as are available */ 03224 if (siFreeFilling<0) { return ( ((Tuint08) (-siFreeFilling)) <= uiTest); } } 03225 /* The default is true, i.e. you get the lock and it remains in effect if the siFreeFilling == 0 or 03226 * we have no queue at all. */ 03227 return true; } 03228 03229 #endif 03230 03231 03232 #if ((cfgUseSynchronization != cfgSyncNon) && ((defUseMutexes == cfgTrue) || (defUseQueus == cfgTrue))) && 0 03233 03234 static void privReleaseSyncBlockingTasks(void) 03235 { /* Arrive here if you have just completed putting sum data on the queue, or used a Mutex 03236 * and are done and have released your own lock. Or call it when the task is 03237 * initilialized or terminated. It runs through all tasks, and unblocks (not unlock) 03238 * the first task that meets the conditions. This may not be the one with the highest 03239 * priority. It does not operate on waitblocks (since they cannot, and should not, 03240 * be released like this) */ 03241 Tuint08 uiLoopTask; 03242 /* Run through all tasks possibly having a slot. */ 03243 for (uiLoopTask=0; uiLoopTask<defNumberOfTasksWithSlot; uiLoopTask++) 03244 { TtaskExtendedControlBlock * loopTCB = (TtaskExtendedControlBlock *) privTcbList(uiLoopTask); 03245 /* First check it this is a blocking task (a non blocking task does not need to 03246 * be released) Furthermore, it must be a task that is able to run, otherwise way 03247 * may release a task which is for instance suspended, and that will hold the lock 03248 * for ever. */ 03249 if ((loopTCB->uiTaskStatus & ( defBaseStopStateGetMask | defBaseModeGetMask | defBaseBlockStateGetMask | defBaseDressGetMask)) == (defBaseStopStateGo | defBaseModeSync | defBaseBlockStateBlocked | defBaseDressSlot) ) 03250 { /* If yes, extract on which slots this task is blocking */ 03251 Tuint08 uiRightSlot = (loopTCB->uiTaskSlot & defSlotRightGetMask) >> defSlotRightShift; 03252 /* Now we must test if this is not a wait-slot */ 03253 #if (defUseWaits == cfgTrue) 03254 if (uiRightSlot < defNumberWaitBegin) 03255 #endif 03256 { /* If we arive here we are dealing with a queue of mutex. Now, depending on if we are working 03257 * with doublelocks, we may need the left slot too. Waits and mutex/queues can never mix, so we 03258 * do not need to worry */ 03259 #if (cfgUseSynchronization == cfgSyncDoubleBlock) 03260 Tuint08 uiLeftSlot = (loopTCB->uiTaskSlot & defSlotLeftGetMask) >> defSlotLeftShift; 03261 /* Now we must test if these slots are unlocked on some other task */ 03262 if (privFreeLockAbsent(uiLeftSlot) && privFreeLockAbsent(uiRightSlot)) 03263 { /* If not, we must test if the filling conditions on this task are fulfilled 03264 * by the queue. If it is a mutex, privSizeFitsQueu returns true per default. If 03265 * we do not have queues at all testing is not needed. */ 03266 #if (defUseQueus == cfgTrue) 03267 if (privSizeFitsQueu(uiLeftSlot,loopTCB->siQueuLeftLock) && privSizeFitsQueu(uiRightSlot,loopTCB->siQueuRightLock)) 03268 #endif 03269 #else 03270 /* Now we must test if these slots are unlocked on some other task */ 03271 if (privFreeLockAbsent(uiRightSlot)) 03272 { /* If not, we must test if the filling conditions on this task are fulfilled 03273 * by the queue. If it is a mutex, privSizeFitsQueu returns true per default. If 03274 * we do not have queues at all testing is not needed. */ 03275 #if (defUseQueus == cfgTrue) 03276 if (privSizeFitsQueu(uiRightSlot,loopTCB->siQueuRightLock)) 03277 #endif 03278 #endif 03279 { /* This task seems to fulfill all requirements to be released. Make it so. */ 03280 privUnblockTask(uiLoopTask | defParaLockStateKeep | defParaRetStateTrue); } } } } } } 03281 03282 03283 #endif 03284 03285 03286 #if ((cfgUseSynchronization != cfgSyncNon) && ((defUseMutexes == cfgTrue) || (defUseQueus == cfgTrue))) 03287 03288 static void privReleaseSyncBlockingTasks(void) 03289 { /* Arrive here if you have just completed putting sum data on the queue, or used a Mutex 03290 * and are done and have released your own lock. Or call it when the task is 03291 * initialized or terminated. It runs through all tasks, and unblocks (not unlock) 03292 * the first task with the highest priority that meets the conditions. When having 03293 * equal priority tasks with a timeout prevail above those without. 03294 * It does not operate on wait blocks (since they cannot, and should not, 03295 * be released like this) */ 03296 /* Variable to run through all tasks. */ 03297 Tuint08 uiLoopTask; 03298 #if (cfgUsePrioritizedRelease == cfgTrue) 03299 /* Variable store the most likely candidate so far. */ 03300 Tuint08 uiSelectedTask; 03301 /* Variable store the modified priority of the most likely candidate so far. */ 03302 Tuint08 uiSelectedLevel = 0; 03303 #endif 03304 /* Run through all tasks possibly having a slot. */ 03305 for (uiLoopTask=0; uiLoopTask<defNumberOfTasksWithSlot; uiLoopTask++) 03306 { TtaskExtendedControlBlock * loopTCB = (TtaskExtendedControlBlock *) privTcbList(uiLoopTask); 03307 /* First check it this is a blocking task (a non blocking task does not need to 03308 * be released) Furthermore, it must be a task that is able to run, otherwise way 03309 * may release a task which is for instance suspended, and that will hold the lock 03310 * for ever. */ 03311 if ((loopTCB->uiTaskStatus & ( defBaseStopStateGetMask | defBaseModeGetMask | defBaseBlockStateGetMask | defBaseDressGetMask)) == (defBaseStopStateGo | defBaseModeSync | defBaseBlockStateBlocked | defBaseDressSlot) ) 03312 { /* If yes, extract on which slots this task is blocking */ 03313 Tuint08 uiRightSlot = (loopTCB->uiTaskSlot & defSlotRightGetMask) >> defSlotRightShift; 03314 /* Now we must test if this is not a wait-slot */ 03315 #if (defUseWaits == cfgTrue) 03316 if (uiRightSlot < defNumberWaitBegin) 03317 #endif 03318 { /* If we arive here we are dealing with a queue of mutex. Now, depending on if we are working 03319 * with doublelocks, we may need the left slot too. Waits and mutex/queues can never mix, so we 03320 * do not need to worry */ 03321 #if (cfgUseSynchronization == cfgSyncDoubleBlock) 03322 Tuint08 uiLeftSlot = (loopTCB->uiTaskSlot & defSlotLeftGetMask) >> defSlotLeftShift; 03323 /* Now we must test if these slots are unlocked on some other task */ 03324 if (privFreeLockAbsent(uiLeftSlot) && privFreeLockAbsent(uiRightSlot)) 03325 { /* If not, we must test if the filling conditions on this task are fulfilled 03326 * by the queue. If it is a mutex, privSizeFitsQueu returns true per default. If 03327 * we do not have queues at all testing is not needed. */ 03328 #if (defUseQueus == cfgTrue) 03329 if (privSizeFitsQueu(uiLeftSlot,loopTCB->siQueuLeftLock) && privSizeFitsQueu(uiRightSlot,loopTCB->siQueuRightLock)) 03330 #endif 03331 #else 03332 /* Now we must test if these slots are unlocked on some other task */ 03333 if (privFreeLockAbsent(uiRightSlot)) 03334 { /* If not, we must test if the filling conditions on this task are fulfilled 03335 * by the queue. If it is a mutex, privSizeFitsQueu returns true per default. If 03336 * we do not have queues at all testing is not needed. */ 03337 #if (defUseQueus == cfgTrue) 03338 if (privSizeFitsQueu(uiRightSlot,loopTCB->siQueuRightLock)) 03339 #endif 03340 #endif 03341 { /* This task seems to fulfill all requirements to be released. */ 03342 #if (cfgUsePrioritizedRelease == cfgTrue) 03343 /* See if it is a candidate. 03344 * By swapping the nibbles we get the priority before the delay status so that we compare 03345 * first on priority and subsequently on delay. (the other bits of the pattern 110dppp1 03346 * are fixed */ 03347 Tuint08 uiCandidateLevel = loopTCB->uiTaskStatus; 03348 portSwapNibbles(uiCandidateLevel); 03349 /* So the candidate level is of the form ppp1110d. If we do not have a selected level yet, 03350 * or the new task is higher */ 03351 if (uiSelectedLevel < uiCandidateLevel) 03352 { /* Copy the new level for further comparison. */ 03353 uiSelectedLevel = uiCandidateLevel; 03354 /* Copy the task number for unblocking at the end. */ 03355 uiSelectedTask = uiLoopTask; } 03356 #else 03357 /* unblock the task. */ 03358 privUnblockTask(uiLoopTask | defParaLockStateKeep | defParaRetStateTrue); 03359 /* we are done. Quickly terminate this loop by increasing the loop task number. 03360 * (do NOT use return here, costs 28 bytes extra! */ 03361 uiLoopTask = defCurrentTaskNumber; 03362 #endif 03363 } } } } } 03364 #if (cfgUsePrioritizedRelease == cfgTrue) 03365 if (uiSelectedLevel != 0) { privUnblockTask(uiSelectedTask | defParaLockStateKeep | defParaRetStateTrue); } 03366 #endif 03367 } 03368 03369 #endif 03370 03371 03372 #if (cfgUseLowPowerSleep == cfgTrue) && (includeTaskSleepAll == cfgTrue) 03373 03374 static void privPutAllTasksToSleep(void) 03375 { /* Call this if you want to put all tasks to sleep. It will put all running and 03376 * blocked, delayed tasks to sleep. If will check if files system operations 03377 * are busy, or if tasks are waiting for fs operations. Those tasks may run 03378 * until the fs actvities are over, and are subsequently put to sleep. It will 03379 * leave suspended and terminated tasks alone. */ 03380 Tuint08 uiLoopTask; 03381 /* Run through all tasks. */ 03382 for (uiLoopTask=0; uiLoopTask<defNumberOfTasks; uiLoopTask++) 03383 { TtaskControlBlock * loopTCB = privTcbList(uiLoopTask); 03384 /* Putting a task to sleep, we do not want to revive a suspended task via the 03385 * sleep. An already sleeping task requires no attention. Thus we must check if 03386 * the task we put to sleep was indeed running. */ 03387 if ((loopTCB->uiTaskStatus & defBaseStopStateGetMask) == defBaseStopStateGo ) 03388 { /* Putting a task blocked on the fs to sleep may lead to a crash at wakeup, 03389 * so putting these tasks to sleep must be postponed until later. In that case 03390 * we will return here. The reason is we have no way to specially store the kind of 03391 * block in a sleepstate, so at wakeup we cannot correctly reconstruct the state. 03392 * It is no problem if the task is actually reading from the file system 03393 * for such a task is not blocked, but writing files cannot be put 03394 * to sleep. First of all, this may lead to data loss, but, second, a sleep 03395 * instruction cannot be effectuated when a burnlock is active. Thus we must 03396 * check if any task is writing. If there are writing tasks, all tasks that 03397 * want to read are readblocked, but if there are no writing tasks, readers 03398 * cannot be blocked, for they are released immediately after the writing 03399 * has finished. Thus we come to the conclusion there is no real need to store 03400 * a read-block-sleeping state. */ 03401 #if (cfgUseFileSystem == cfgTrue) 03402 /* Thus we exclude all those tasks from sleeping if the fs writeblock is activated 03403 * which are in read or write mode. (We cannot test for writeblock itself, since 03404 * there is always one task actually writing and not blocking. */ 03405 if ( ((uiFsStatus & defFsWriteBlockGetMask) == defFsWriteBlockClear) || 03406 ((loopTCB->defFsField & (defFsReadGetMask | defFsWriteGetMask)) == (defFsReadClear | defFsWriteClear)) ) 03407 #endif 03408 /* Change the status to sleeping */ 03409 { loopTCB->uiTaskStatus = (loopTCB->uiTaskStatus & defBaseSleepingSetMask) | defBaseSleepingTask; } } } } 03410 03411 #endif 03412 03413 03414 #if (cfgUseFileSystem == cfgTrue) 03415 03416 static void privReleaseFileBlocks(void) 03417 { /* Call this method after you are done with file operations on a task and new tasks 03418 * may be given the opportunity to be released. Usually this is after a fileClose on 03419 * a file write operation, or after all reads are finished. */ 03420 /* First check if we have more task on the file system. If not, we can only arrive 03421 * here if the current (and only!) task has completed read or write operations and 03422 * closes the access to the file system. Now, since there are no other tasks that 03423 * may want access we have little to do. */ 03424 #if (defUseFsOnMultipleTasks == cfgTrue) 03425 /* It seems we have. We have to see in which state the file system is 03426 * Check if we have a write lock. When we have a write lock there must be at least 03427 * one task actually writing, so it makes no sense to release anything. When we don't 03428 * have a write lock we may have a read lock (i.e. there are tasks actually reading, but 03429 * we still search for tasks that may want to write. If we find these, we should not 03430 * accept new reads, until the tasks wanting to write has had the opportunity to do so. */ 03431 if ((uiFsStatus & defFsWriteBlockGetMask) == defFsWriteBlockClear) 03432 { /* It seems we don't have a write task, so loop through all tasks and search 03433 * for write blocks. We only search in those tasks making use of the file system. */ 03434 Tuint08 uiLoopTask; 03435 for (uiLoopTask=defTaskNumberFileSystemBegin; uiLoopTask<defTaskNumberFileSystemEnd; uiLoopTask++) 03436 { /* Now we must check if this is indeed a task with a file block (it could be an other kind of block) and if this 03437 * block is in the write mode. */ 03438 if ((privTcbList(uiLoopTask)->uiTaskStatus & (defBaseFileBlockedGetMask | defBaseDressGetMask)) == (defBaseFileBlockedTask | defBaseDressWrite)) 03439 { /* All right, this task is waiting for an opportunity to write to the file system. 03440 * There are two possibilities, or we can directly deblock to a lock, or we must issue 03441 * a write request. In both cases we must activate the write block in the file system 03442 * status (If there is already a read block present, this write block works as a local 03443 * flag signaling that a task is waiting for write access. Note we can never arrive here 03444 * in the other situation where both read and write block are activated, namely a writing 03445 * task waiting for file close. */ 03446 uiFsStatus = (uiFsStatus & defFsWriteBlockSetMask) | defFsWriteBlockActive; 03447 /* If there is not single-write-multiple-read synchronizer active, read blocks are not 03448 * possible (we read under the write lock, this is always permitted. */ 03449 #if (cfgUseFileSystemConcurrentRead == cfgTrue) 03450 /* Now, if the read block is set we are done, cause the write request is already set, 03451 * nothing more can be done. In case it is not set, we may appoint access to the current 03452 * task, and give it write access. */ 03453 if (((uiFsStatus & defFsReadBlockGetMask) == defFsReadBlockClear)) 03454 #endif 03455 { /* Here we must activate the task for writing, which implies that its task number is put into 03456 * the first nibble of the FsStatus. Furthermore, we clear the burn lock (it should already be 03457 * cleared btw). */ 03458 uiFsStatus = ((uiFsStatus & (defFsBurnBlockSetMask & defFsWriteNumberSetMask)) | (defFsBurnBlockClear | (uiLoopTask << defFsTaskNumberShift) ) ); 03459 /* The task was already blocked (we tested that, and besides, every task is blocked at 03460 * file-open per default). So we must unblock, but keep the lock. */ 03461 privUnblockTask(uiLoopTask | defParaLockStateKeep | defParaRetStateTrue); } 03462 break; } } } 03463 /* If we have simultaneous read possibility we must do some more research. */ 03464 #if (cfgUseFileSystemConcurrentRead == cfgTrue) 03465 /* It may seem strange, but we start again by looking at the WriteBlokc bit in the 03466 * FS status. If the bit is set, there are two possibilities. First, the read bit is 03467 * still cleared, so there is write action, and no further action with respect to reading 03468 * is needed. If the read bit is set also, it must be been set before we entered this method, 03469 * and the write bit must be interpreted as write request. In that case no new read tasks 03470 * may be activated. Same result, nothing to do. */ 03471 if ((uiFsStatus & defFsWriteBlockGetMask) == defFsWriteBlockClear) 03472 { /* No write bit, thus there is room for a new read task. Run through all tasks. */ 03473 Tuint08 uiLoopTask; 03474 for (uiLoopTask=defTaskNumberFileSystemBegin; uiLoopTask<defTaskNumberFileSystemEnd; uiLoopTask++) 03475 { /* Now we must check if this is indeed a task with a file block (it could be an other kind of block) and if this 03476 * block is in the read mode. */ 03477 if ((privTcbList(uiLoopTask)->uiTaskStatus & (defBaseFileBlockedGetMask | defBaseDressGetMask)) == (defBaseFileBlockedTask | defBaseDressRead)) 03478 { /* This task want to perform a read action. This is certainly possible, without further restrictions 03479 * since reading may be done in parallel. */ 03480 uiFsStatus = ((uiFsStatus & defFsReadBlockSetMask) | defFsReadBlockActive); 03481 /* We count the number of read tasks in the least significant nibble of the FS status. If this is 03482 * the first read task, we can be certain the number is zero to start with. It has been cleared 03483 * after the last write operation, or has been cleared by down counting the last read operations. */ 03484 uiFsStatus += defFsReadInc; 03485 /* Release a task for reading. It was already blocked, we switch it to lock. Since this kind 03486 * of call may timeout, we return true. */ 03487 privUnblockTask(uiLoopTask | defParaLockStateKeep | defParaRetStateTrue); } } } 03488 else 03489 { /* If we indeed have write request, we must clear that flag, since it must be a local 03490 * flag. Outside this method, activating both read and write blocks is interpreted 03491 * as a closing write tag. */ 03492 if ((uiFsStatus & defFsReadBlockGetMask) == defFsReadBlockActive) 03493 { /* Both flags are active, the write block must be cleared. */ 03494 uiFsStatus = ((uiFsStatus & defFsWriteBlockSetMask) | defFsWriteBlockClear); } } 03495 #endif 03496 #endif 03497 /* If we make use of low power sleep, putting task to sleep who perform file operations is a 03498 * delicate matter. Inside the sleepAll method the sleep request bit on the FS status has been 03499 * activated. As soon as all tasks have completed file write access, and this is the place to test, 03500 * we may retry to put some or all tasks to sleep. This situation is equal for one and more tasks 03501 * on the file system. */ 03502 #if (cfgUseLowPowerSleep == cfgTrue) && (includeTaskSleepAll == cfgTrue) 03503 /* If we want to put a task to sleep all blocks must be resolved and no task may be writing. 03504 * This is however not the point to check this. If we arrive here we know for sure that there is 03505 * one task who finished writing or reading operations. Thus if we requested for sleep, we give it 03506 * an other try. */ 03507 if ((uiFsStatus & defFsSleepRequestGetMask) == defFsSleepRequestActive) { privPutAllTasksToSleep(); } 03508 #endif 03509 } 03510 03511 #endif 03512 03513 03514 #if (cfgUseFileSystem == cfgTrue) 03515 03516 static Taddress privFileLocation(Tuint08 uiFileNumber, Tuint08 uiOffset) 03517 { /* Use this method to find the location of a particular file in eeprom. The lengths 03518 * of all predefined files are determined at compile time and are stored in flash. 03519 * Since all files are placed just one after the other, starting with the first 03520 * file after the 'fat', calculation of the location is easy. 03521 * We fill the location pointer with the location of the first file (number 0) and the 03522 * offset. Note that this location in itself may mean nothing. */ 03523 #if (cfgUseFileSystemMaintainFAT == cfgTrue) 03524 /* If we make use of a FAT, we must correct for its size. For every file one byte containing its length. */ 03525 Tuint16 pFileLoc = defFsNumberOfAllFiles + uiOffset; 03526 #else 03527 /* When there is no FAT, files start at the bottom of the eeprom. */ 03528 Tuint16 pFileLoc = uiOffset; 03529 #endif 03530 /* Now test if we have a predefined file or a default file */ 03531 if (uiFileNumber >= defFsNumberOfPreFiles) 03532 { /* Correct the start address for default files, which is known at compile time. */ 03533 pFileLoc += ((Tuint16) (uiFileNumber-defFsNumberOfPreFiles))*FileSpaceStandard + defTotalPreFileSpace; } 03534 else 03535 { /* Determine if we have equal sized files or if we have different sizes per file. */ 03536 #if (defFilePreSpaceConstant == cfgTrue) 03537 /* All named files have the same size, so */ 03538 pFileLoc += uiFileNumber * defFilePreSpaceFixed; 03539 #else 03540 /* in flash we have stored the length of all predefined files, which we must subsequently add. */ 03541 while(uiFileNumber--) 03542 { /* Read the length of all predefined files from flash, and add it to the location: */ 03543 pFileLoc += portFlashReadByte(Tuint08,uiFileSpace[uiFileNumber]); } 03544 #endif 03545 } 03546 /* at this moment we have the correct start address in eeprom, return it. */ 03547 return (Taddress) pFileLoc; } 03548 03549 #endif 03550 03551 03552 #if (cfgUseFileSystem == cfgTrue) && ( ((cfgUseFileSystemMaintainFAT == cfgTrue) && (includeTaskFileAppendByte == cfgTrue)) || (cfgCheckMethodUse == cfgTrue) ) 03553 03554 static Tuint08 privFileSpace(Tuint08 uiFileNumber) 03555 { Tuint08 uiResult; 03556 /* Use this to obtain the space available for a file. If the file is a default file ... */ 03557 if (uiFileNumber >= defFsNumberOfPreFiles) 03558 { /* ... the answer is simple */ 03559 uiResult = FileSpaceStandard; } 03560 else 03561 { /* Determine if we have equal sized files or if we have different sizes per file. */ 03562 #if (defFilePreSpaceConstant == cfgTrue) 03563 /* fixed sizes */ 03564 uiResult = defFilePreSpaceFixed; 03565 #else 03566 /* otherwise we must look it up from a table in flash. */ 03567 uiResult = portFlashReadByte(Tuint08,uiFileSpace[uiFileNumber]); 03568 #endif 03569 } 03570 return uiResult; } 03571 03572 #endif 03573 03574 03575 #if (cfgUseFileSystem == cfgTrue) 03576 03577 static void privPrepareFileClose(Tuint08 uiTaskNumber) 03578 { /* Call this method to close the access to a file. You can also call it if the task does 03579 * not hold a file, if defUseFsField is activated. In that case no action is taken. 03580 * These are the situations that are handled 03581 * (1) FS-WriteBlock and current task holds write lock => close writing operations, maybe issue a release request. 03582 * (2) FS-WriteBlock and current task holds write block => do nothing, there is nothing to be closed 03583 * (3) FS-WriteBlock and current task holds read lock => do nothing, there is nothing to be closed 03584 * (4) FS-ReadBlock and current task holds write lock => do nothing, there is nothing to be closed 03585 * (5) FS-ReadBlock and current task holds read lock => current task must be reading, close 03586 * (6) FS-ReadBlock & FS-WriteBlock and current task holds write lock => current task is waiting for closing, do nothing 03587 * (7) FS-ReadBlock & FS-WriteBlock and current task holds write block => other task is waiting closing, do nothing. 03588 */ 03589 #if (defUseFsField == cfgTrue) 03590 TtaskControlBlock * taskTCB = privTcbList(uiTaskNumber); 03591 #endif 03592 /* First we test if the FS write block is set. */ 03593 if (((uiFsStatus & defFsWriteBlockGetMask) == defFsWriteBlockActive)) 03594 { /* If there is a chance we arrive here from an other place than the current task we must test if 03595 * the task at hand is the one the FS write block is holding. If not, this must coincide, and we 03596 * can leave this piece of code out. */ 03597 #if (defUseFsField == cfgTrue) 03598 /* We must sort out of the requested task for closing is indeed writing at the moment. If not, 03599 * there is nothing to close. */ 03600 #if (defUseFsOnMultipleTasks == cfgTrue) 03601 /* If we have more tasks writing, we cannot just check the fsfield, for all tasks 03602 * writing are in the write mode. The number of the task writing is contained in 03603 * the status. If this matches we do not need to check if the task is in write mode 03604 * any more. This must be the case. One special case is if we come from the closeFile call, 03605 * this call simply supplies the current file number, which should we fine. (It is an error 03606 * to call closeFile on a task that does not have a file open.*/ 03607 if ((uiTaskNumber == ((uiFsStatus & defFsWriteNumberGetMask) >> defFsTaskNumberShift)) || (uiTaskNumber == defCurrentTaskNumber)) 03608 #else 03609 /* If we have one possible task writing, we can just check the fsfield, if it 03610 * is set this must be the one. There are no other blocking ones. */ 03611 if ((taskTCB->defFsField & defFsWriteGetMask) == defFsWriteActive) 03612 #endif 03613 #endif 03614 { /* We may come here with burn block activated if the current write task was still writing while 03615 * being killed. In that case we must put the fs in release request state. The task must still 03616 * be properly closed. Start with the latter. */ 03617 #if (defUseFsField == cfgTrue) 03618 /* Apart from the FsStatus this is all we need to do. */ 03619 taskTCB->defFsField = (taskTCB->defFsField & defFsWriteSetMask) | defFsWriteClear; 03620 #endif 03621 /* Now test the burn block. */ 03622 if (!portFSWriteReady()) 03623 { /* Ok we have a burn block, thus, inform the outside world */ 03624 privTrace(traceBurnLock); 03625 /* Set the release request (contains burn block), leave a possible sleep request intact */ 03626 uiFsStatus = (uiFsStatus & defFsFreeSetMask) | defFsSetReleaseRequest ; } 03627 else 03628 { /* Clear everything in the status register, except a possible request for sleep. */ 03629 uiFsStatus = (uiFsStatus & defFsFreeSetMask) | defFsFree; 03630 /* Since we have no burn block we may release new tasks. */ 03631 privReleaseFileBlocks(); } } } 03632 /* Only if we make use of simultaneous reads, we have read blocks. */ 03633 #if (cfgUseFileSystemConcurrentRead == cfgTrue) 03634 /* This else is needed otherwise this function may treat release requests for write blocked tasks. We do not want that. */ 03635 else 03636 { /* Check if we are dealing with an FS read block*/ 03637 if ((uiFsStatus & defFsReadBlockGetMask) == defFsReadBlockActive) 03638 { /* OK we are reading indeed. This means that if we are dealing with the current task we must be reading, and 03639 * otherwise we must check this. Since this function may be called for any task from TaskInit of Terminate. */ 03640 #if (defUseFsField == cfgTrue) 03641 if ((taskTCB->defFsField & defFsReadGetMask) == defFsReadActive) 03642 #endif 03643 { /* And clear the read mode of that task when present. */ 03644 #if (defUseFsField == cfgTrue) 03645 taskTCB->defFsField = (taskTCB->defFsField & defFsReadSetMask) | defFsReadClear; 03646 #endif 03647 /* If we have more tasks reading, we must keep track of the number of tasks, if not 03648 * the matter is simpler.*/ 03649 #if (defUseFsOnMultipleTasks == cfgTrue) 03650 /* Now we are sure this task is indeed reading. Remove one reader from the read counter. */ 03651 uiFsStatus -= defFsReadInc; 03652 /* Now we must check if there are any reading tasks left. This could be the last. 03653 * Shifting with defFsReadCount is not needed since we only need to compare with zero. */ 03654 if ((uiFsStatus & defFsReadCountGetMask) == 0) 03655 { /* If there are not readers left, clear the FS read block. */ 03656 uiFsStatus = ((uiFsStatus & defFsReadBlockSetMask) | defFsReadBlockClear); 03657 /* And check if there are new tasks waiting to read. */ 03658 privReleaseFileBlocks(); } 03659 #else 03660 /* We are the only reader so clean the block. */ 03661 uiFsStatus = ((uiFsStatus & defFsReadBlockSetMask) | defFsReadBlockClear); 03662 /* Although there cannot be any other tasks, there can be sleep request. */ 03663 privReleaseFileBlocks(); 03664 #endif 03665 } } } 03666 #endif 03667 /* Done, we handled writing as well as reading. */ } 03668 #endif 03669 03670 03671 #if (cfgCheckTaskStack == cfgTrue) && (StackSafety > 0) 03672 03673 void privTestStackRegion(void) 03674 { Tuint08 uiTaskNumber = privTaskNumber(defCurrentTaskNumber); 03675 /* Get the size of the stack */ 03676 #if (defStackSizeConstant == cfgTrue) 03677 /* When we use a constant size, we are quickly done. */ 03678 Tstack uiStackSize = defStackSizeFixed; 03679 #else 03680 /* Otherwise we must get that from flash too. */ 03681 Tstack uiStackSize = portFlashReadStruc(TtaskDefinitionBlock,pxTDBlist[uiTaskNumber],Tstack,uiStackSize); 03682 #endif 03683 /* Now we have the stack size we may first compare it to the stack level. If the latter exceeds the former 03684 * there is no need to check any further, we must be in error, get the tcb */ 03685 TtaskControlBlock * taskTCB = privTcbList(uiTaskNumber); 03686 /* compare the values. Note that for one byte levels it may happen that the values roled over, we cannot 03687 * detect that situation here. */ 03688 if (taskTCB->pcStackLevel > uiStackSize) 03689 { /* probably the error was already reported as non fatal, but is becomes fatal now, because we are certain 03690 * the tasks violated the boundaries. */ 03691 privShowError((fatTaskStackOverflowed | errTaskStateCurrent), callIdSystem, errCurrentTask ); } 03692 /* Get the location where the stack starts. */ 03693 Taddress pcStackOffset = portFlashReadStruc(TtaskDefinitionBlock,pxTDBlist[uiTaskNumber],Taddress,pcStackOffset); 03694 #if (cfgSysStackGrowthUp == cfgTrue) 03695 /* TODO: cfgSysStackGrowthUp oops, add code */ 03696 Taddress pSafetyByte = 0; 03697 #else 03698 /* Calculate the location of the first byte that should by clean. Note that, at a value of 03699 * StackSafety == 0, this points at a place outside the stack of the current task. */ 03700 Taddress pSafetyByte = pcStackOffset+StackSafety-uiStackSize; 03701 #endif 03702 /* Now see if the safety area is indeed clean. The maximum size of the StackSafety parameter 03703 * is 0xFF, so the counter must fit one byte. */ 03704 Tuint08 uiCount; 03705 for (uiCount=0; uiCount<StackSafety; uiCount++) 03706 { /* read the value of the stack in the 'virginity' area. None of the values may have 03707 * a different value. */ 03708 #if (cfgSysStackGrowthUp == cfgTrue) 03709 if (*(pSafetyByte++) != defStackInitByte) 03710 #else 03711 if (*(pSafetyByte--) != defStackInitByte) 03712 #endif 03713 { /* So the first one to differ is bingo. Note this is a fatal error since other stacks 03714 * may have been damaged as well. */ 03715 privShowError((fatTaskStackOverflowed | errTaskStateCurrent), callIdSystem, errCurrentTask ); } } } 03716 03717 #endif 03718 03719 03720 03721 #if (cfgUseLowPowerSleep == cfgTrue) 03722 03723 void privWakeupFromLowPower(void) 03724 { /* The tick timer could have made several rounds. We ignore these, since this is (must be) 03725 * corrected manually. Further, we set the next interrupt far away, we do not want any 03726 * hanging interrupts. */ 03727 #if (cfgUseEquidistantTicks == cfgFalse) 03728 portReadAndResetTimer(defSubTicksMax); 03729 #endif 03730 /* Now the time has come to loop trough all the sleeping tasks and kiss them. */ 03731 Tuint08 uiLoopTask; 03732 for (uiLoopTask=0; uiLoopTask<defNumberOfTasks; uiLoopTask++) 03733 { TtaskControlBlock * loopTCB = privTcbList(uiLoopTask); 03734 /* Check if the loopTask is indeed in the sleep state. */ 03735 if ((loopTCB->uiTaskStatus & defBaseSleepingGetMask) == defBaseSleepingTask) 03736 { /* Wake the task. */ 03737 loopTCB->uiTaskStatus = (loopTCB->uiTaskStatus & defBaseStopStateSetMask) | defBaseStopStateGo; 03738 /* First, however we must check what kind of task it is. In case this is a shared task, 03739 * we may not wakeup just like that, but must return to the shared mode. Fortunately, 03740 * the shared task could no be blocking when in shared state, so the sleep state could 03741 * not be in a blocked mode either. So the only thing we have to do is to bring it 03742 * to mode access. */ 03743 #if (defUseSharedStack == cfgTrue) 03744 /* The the stacklevel, if empty, */ 03745 if (loopTCB->pcStackLevel == defStackEmpty) 03746 { /* then we had a shared task in shared mode. Because the state could not be blocking, and 03747 * the StopState is already go, we only need to flip this bit. */ 03748 loopTCB->uiTaskStatus = (loopTCB->uiTaskStatus & defBaseModeSetMask) | defBaseModeAccess; } 03749 #endif 03750 /* When we keep track of the exact wake up moments, this is on of the places to store 03751 * the wake time. Of course, for accurate frequencies, the tick counter must already be 03752 * manually corrected. */ 03753 #if (cfgUseDelay == cfgTrue) && (cfgUseCorrectWakeupTimes == cfgTrue) 03754 /* We must be careful with one situation. A sleeping task could be delayed also, and 03755 * the delay may not yet be finished. If so, we must not destroy the delay time 03756 * variables, for which there is no need also, since the should already contain the 03757 * correct wakeup time in the future. */ 03758 if ((loopTCB->uiTaskStatus & defBaseDelayStateGetMask) == defBaseDelayStateWake) 03759 { loopTCB->uxDelay.Full = uxTickCount.Full; } 03760 #endif 03761 } } 03762 /* DISCUSSION 03763 * If there were sleeping tasks that were blocking or did possess some slots, is that 03764 * a problem? In other words, should we release some blocking tasks at this place? 03765 * Well, you can only call sleep on you yourself, and if you so, you cannot block, but 03766 * you may possess slots. Of course it is very dangerous to put a task that is possessing 03767 * a mutex to sleep, since it will only be released at the next wakeup. We assume that if 03768 * you do, you know what you are doing. The other possibly is that all tasks were put 03769 * sleep simultaneously. Then, since they also wakeup simultaneously again, there is no 03770 * danger in having dangling blocks. Thus, since there can be no dangling blocks with 03771 * the sleep feature, there is no need to call privReleaseSyncBlockingTasks() at this place. 03772 */ } 03773 03774 #endif 03775 03776 #if (defCheckReportingError == cfgTrue) 03777 void privInitOs(Tuint08 uiErrorControl) 03778 #else 03779 void privInitOs(void) 03780 #endif 03781 { /* DISCUSSION 03782 * After a context switch we always enter here. We shall make all necessary preparations 03783 * to correctly handle the situation. That is, check if the task has run properly, 03784 * First thing to do is to perform the checks. This is needed since all this data is 03785 * stored in background variables. These are destroyed as soon as we make use of the stack. 03786 * This is the moment and the place to state that we are actually running the OS. We 03787 * certainly need to do it before we reactivate the interrupts, since we want to be 03788 * able to ask, inside the interrupt, where the system was. But it is unwise due to the 03789 * stack use (an temporal variable will be push unto the stack) therefore we use 03790 * a trick, and set the state twice. See below. This seems to cost more code, but 03791 * actually reduces the code when compiled without checks. Which checks its a 03792 * little longer, but makes sure no variables are pushed unto the stack at the 03793 * beginning of the compiled routine. */ 03794 03795 /* We can start checking the results from the context save. */ 03796 #if (cfgCheckTaskStack == cfgTrue) || (cfgCheckRegisters == cfgTrue) || (cfgCheckWatermarks == cfgTrue) 03797 /* These checks are only sensible if we where previously performing a task */ 03798 if ((uiOsStatus & defContextGetMask) == defContextStateTask) 03799 { /* The watermark checks are meant to measure to what extend use is made of the stack and the 03800 * registers. The maximal value of the stack level is recorded here, since this place is one 03801 * of the placed probably consuming most of the stack. If we set the TDB uiRegisterUse to 0xFF 03802 * the real register use can here be collected. Note that the value of uiStackMax is only 03803 * correct when there was no stack error, since in that case the context 03804 * was not saved at all. 03805 * We first check the watermarks and after that the register use and 03806 * stack use since if the latter result in an error the background variables are corrupted 03807 * leading to incorrect watermarks. In the situation we have checking activated we have 03808 * three bumper variables (6 bytes) in the stack which are just consumed by the the call to privInitOs 03809 * and to privTcbList(defCurrentTaskNumber). So our safety is two bytes. Note that this is a delicate 03810 * matter, if the compiler decides to push some more variables at the start of privInitOs() or 03811 * privTcbList(defCurrentTaskNumber) this result is faulty. */ 03812 #if (cfgCheckWatermarks == cfgTrue) 03813 TtaskControlBlock * curTCB = privTcbList(privTaskNumber(defCurrentTaskNumber)); 03814 if ((curTCB->uiStackMax)<(curTCB->pcStackLevel)) { curTCB->uiStackMax = (curTCB->pcStackLevel); } 03815 /* uiRegisterCheck contains the result of the check on the register use, i.e. all register blocks 03816 * used are marked by a bit set. */ 03817 curTCB->uiRegisterUse |= xOS.pxSave.uiRegisterCheck; 03818 #endif 03819 /* Check if we did not exceed the stack. In fact, in most cases this check is if we 03820 * would have exceeded the stack, given we would have saved the entire context. In the 03821 * portSaveContext however, we first calculated if the context fits in the remaining 03822 * stack space, if not, the context is not saved, and uiStackTCheck indicates a stack error. Of course 03823 * we can never restart that task, but that would not have been possible in a reliable way 03824 * anyhow. Now, at least we may have reduced the damage to other parts of the memory. */ 03825 #if (cfgCheckTaskStack == cfgTrue) 03826 if ((xOS.pxSave.uiStackTCheck & defCheckStackGetMask) == defCheckStackStateError) 03827 { /* Now we can have two situations. First the stack may be overflown already, which is 03828 * is an fatal error since most likely other tasks are damaged as well, or the context 03829 * may not fit the stack. The former cannot be detected with 100% certainty, but if we can 03830 * see it has happened, we should issue an fatal error */ 03831 privShowError((errTaskStackWillOverflow | errTaskStateCurrent | uiErrorControl), (callIdSystem | defContextStateOs), errCurrentTask ); } 03832 /* Since issuing an error damages the background variables it makes no sense to check for registers 03833 * is an error occurred here. Furthermore, because an detected error in the stack size will skip the 03834 * proper checking of register use, that information is not reliable may indicate a false error. 03835 * therefore we must report an error in the stack check before an error in the registers, and refrain 03836 * from reporting the latter. */ 03837 else 03838 #endif 03839 /* Check if the task has used registers that it did say it would not. In the portSaveContext all 03840 * registers used are scanned, and one byte of information is build, uiRegisterCheck, which 03841 * contains set bits at the appropriate places. Now, this byte is compared with the proclaimed 03842 * use of registers, uiRegisterUse. Any bit outside this mask indicates an error. 03843 * Please note that this error does not have to be fatal. Since, it may be that some registers 03844 * are used only within a realm in which no task context switch is possible. That registers need 03845 * not to be saved. So an error here may be ignored if you know what you are doing. For the 03846 * moment however, we decide to stop the task anyway.*/ 03847 #if (cfgCheckRegisters == cfgTrue) 03848 { /* Determine which register blocks where used without authorization, that are all register blocks 03849 * used (the ones not check are already set to zero) excluding any of the blocks where use 03850 * is allowed. */ 03851 Tuint08 uiRegisterViolation = xOS.pxSave.uiRegisterCheck & ~xOS.pxSave.uiRegisterUse; 03852 /* If there is any such block we must report an error */ 03853 if (uiRegisterViolation != 0) 03854 { /* We determine the highest block number in violation, that could be 7 (regs 28,29,30,31)*/ 03855 Tuint08 uiRegBlock = 7; 03856 /* Check if this is indeed so */ 03857 while ( (uiRegisterViolation & 0x80) == 0 ) 03858 { /* If not it could be 6, so we decrease the counter one ... */ 03859 uiRegBlock--; 03860 /* and shift the 6th block to the 7th */ 03861 uiRegisterViolation <<= 1; } 03862 /* By now we have found that block, report the error, the faulty block in the slot slot. */ 03863 privShowError((errTaskIllegalRegisterUse | errTaskStateCurrent | uiErrorControl), (callIdSystem | defContextStateOs), (uiRegBlock << errInfoNumberShift) | errCurrentTask); } } 03864 #else 03865 /* Empty statement to close a possible dangling else from (cfgCheckTaskStack == cfgTrue) */ 03866 { } 03867 #endif 03868 /* Here we are going to check if the bytes in the safety zone are untouched, if not the 03869 * task has written in the forbidden area, and since it may have surpassed that area, 03870 * other tasks may have been damaged. The check only makes sense if we have a safety area. 03871 * Note that this is done inside a function that is only called once, but is not allowed 03872 * to be inlined. This is because it will cause to much stack use in privInitOs. The 03873 * call or returns without error, or causes a fatal error.*/ 03874 #if (cfgCheckTaskStack == cfgTrue) && (StackSafety > 0) 03875 privTestStackRegion(); 03876 #endif 03877 } 03878 #endif 03879 /* Interrupts. That is an interesting case. We have different models of interrupt handling and OS 03880 * protection in the Femto OS. That is discussed elsewhere. In general, global interrupts are disabled when 03881 * we arrive here, this is done in all methods calling the saveContext (and not in the saveContext 03882 * itself!). Thus if we want to protect the OS against interrupts, we do not have to do anything 03883 * here. If this protection is not needed, we must reactivate the interrupts. This must be done 03884 * in two stages. We must be sure we do not get a tick interrupt while being in the OS, since 03885 * we would not know how to react (but, in general such an interrupt will not come since it would 03886 * indicate a tick rate to high), and then we may reactivate the global interrupts. 03887 * The default situation inside the OS is deactivated tick interrupts, and that has been taken care of 03888 * in the portSaveContext. Thus we only have to */ 03889 #if (cfgIntOsProtected == cfgFalse) 03890 privEnableGlobalInterrupts(); 03891 #endif 03892 /* If we included the use of the Low Power sleep ... */ 03893 #if (cfgUseLowPowerSleep == cfgTrue) 03894 /* ... and if we come from a 'sleep task', i.e.. if we have been in a low power sleep, there is some work to 03895 * be done. We assume that delay tasks have already been woken and the tick counter has already 03896 * been corrected. Do the test */ 03897 if ((uiOsStatus & defContextGetMask) == defContextStateSleep) 03898 { /* Restore the status of all the tasks to their original values. */ 03899 privWakeupFromLowPower(); } 03900 #endif 03901 /* If we allow for time measurement in isr's, we must show how remember in what state we 03902 * were before the interrupt occurred. This only works for the interrupts that invoke 03903 * a context switch first. */ 03904 #if (cfgUseLoadMonitor == cfgTrue) && (cfgIntUserDefined == cfgTrue) && (cfgIntOsProtected == cfgTrue) && (cfgUseLowPowerSleep == cfgFalse) && (cfgIntTickTrack == cfgFalse) 03905 uiLastOsStatus = uiOsStatus; 03906 #endif 03907 /* If we have synchronization tasks and make use of the return values of some functions trying 03908 * to obtain locks, we must set the return values to Non. The method that will release the task 03909 * will fill the variable with the appropriate value. This is the correct place for that instruction 03910 * since we do not know if we indeed will switch the task. The task may not be switched at all. */ 03911 #if (cfgUseSynchronization != cfgSyncNon) && (defUseBoolReturns == cfgTrue) 03912 { TtaskControlBlock * curTCB = privTcbList(privTaskNumber(defCurrentTaskNumber)); 03913 curTCB->defRetField = (curTCB->defRetField & defRetSetMask) | defRetNon; } 03914 #endif 03915 } 03916 03917 03918 #if ((cfgIntUserDefined == cfgTrue) && (cfgUseLoadMonitor == cfgTrue) && ((includeIsrEnter == cfgTrue) || (includeIsrStartLoad == cfgTrue))) 03919 03920 void isrStartLoad(void) 03921 { /* IsrLoad measures the total time spend in interrupts. We must fill it with the actual value 03922 * of the subtick timer. This is true in both cases, equidistant ticks or not. Now we want to 03923 * collect the number of subticks spend in the interrupt. Thus we subtract the current value of the 03924 * subtick counter. If the uiIsrLoadTemp underflows that is not a real problem, as long as it 03925 * does not underflow twice, which does not happen easily. Since we may assume that during 03926 * the isr there will be no tick interrupt, the portReadTimer will keep returning increasing 03927 * values, even if the timer reset, since the interrupt was not handled. */ 03928 uiIsrLoadTemp -= portReadTimer(); } 03929 03930 #endif 03931 03932 03933 #if ((cfgIntUserDefined == cfgTrue) && (cfgUseLoadMonitor == cfgTrue) && ((includeIsrExit == cfgTrue) || (includeIsrStopLoad == cfgTrue))) 03934 03935 void isrStopLoad(void) 03936 { /* After the interrupt is done, we simply add the new value of the timer to get the 03937 * time spend in the interrupt. If we have more interrupts during a task (this time registration 03938 * also works in case of absence of OS protection, they are automatically added. */ 03939 uiIsrLoadTemp += portReadTimer(); } 03940 03941 #endif 03942 03943 03944 #if (cfgIntUserDefined == cfgTrue) && (cfgIntOsProtected == cfgTrue) && (includeIsrExit == cfgTrue) 03945 03946 void privIsrExit(void) 03947 { /* Arrive here when you end the interrupt. This method pairs with the IsrEnter routine. 03948 * First switch back to the OS stack. Even if we executed the isr in OS space it is necessary 03949 * to reset the stack. */ 03950 privSetStack(&xOS.StackOS[OSstackInit]); 03951 /* When using the load monitor we need to know what the last state was, before we switch to a new 03952 * one. This was saved in uiLastOsStatus. */ 03953 #if (cfgUseLoadMonitor == cfgTrue) && (cfgUseLowPowerSleep == cfgFalse) && (cfgIntTickTrack == cfgFalse) 03954 /* We must pas the idle state as an active bit (all other calls 03955 * on privEnterOS should not pass extra information because of this special situation, thus the 03956 * default is run/isr state). If the idle state has been running can be seen on the defContextStateIdle 03957 * bit. But this is also set if there was an isr. By the calculation below we isolate the information, 03958 * and uiIdleAction only has a bit set on defActionRunStateIdle is the state was idle. */ 03959 Tuint08 uiIdleAction = (~uiLastOsStatus) & defActionRunGetMask; 03960 #else 03961 /* These is no need to pass information about the idle state. */ 03962 Tuint08 uiIdleAction = 0; 03963 #endif 03964 /* Start the OS, stating that we want an task switch. */ 03965 privEnterOS(uiIdleAction | defActionTaskStateSwitch); } 03966 03967 #endif 03968 03969 03970 #if ((cfgUseEquidistantTicks == cfgFalse) && (cfgCheckTiming == cfgTrue)) 03971 03972 void privSubtickOverflow(void) 03973 { /* This method is only called from the subtick timer overflow interrupt. It indicates that 03974 * the subtick timer overflowed, thus loosing full ticks, a condition which should not 03975 * occur. The only thing to do is to report the error, which is fatal. */ 03976 privShowError((fatTaskSubtickOverflow | errTaskStateCurrent), callIdSystem, errCurrentTask ); } 03977 03978 #endif 03979 03980 03981 void privTickYield(void) 03982 { /* Arrive here from a tick interrupt. It is assumed that global interrupts are already switched off. 03983 * We know we came from a tick, so the global interrupt must have been on before, make sure, the 03984 * task starts with global interrupts activated when restored. */ 03985 portResqueGlobalInterruptActive(); 03986 /* Since we have no parameters, we may safely save the context now. */ 03987 portSaveContext(); 03988 /* When using the load monitor we need to know what the last state was, before we switch to a new 03989 * one. Now, this can only be obtained from the uiOsStatus, since there are no special numbers 03990 * for the isr's and the idle state kept.*/ 03991 #if (cfgUseLoadMonitor == cfgTrue) 03992 /* We must pas the idle state as an active bit (all other calls 03993 * on privEnterOS should not pass extra information because of this special situation, thus the 03994 * default is run/isr state). If the idle state has been running can be seen on the defContextStateIdle 03995 * bit. But this is also set if there was an isr. By the calculation below we isolate the information, 03996 * and uiIdleAction only has a bit set on defActionRunStateIdle is the state was idle. */ 03997 Tuint08 uiIdleAction = (~uiOsStatus) & defActionRunGetMask; 03998 #else 03999 /* These is no need to pass information about the idle state. */ 04000 Tuint08 uiIdleAction = 0; 04001 #endif 04002 /* After saving the context (all registers are preserved, and the stack is switched, we initialize 04003 * the OS. */ 04004 privInitOsReturn(); 04005 /* Inform that we interrupted the task*/ 04006 privTrace(traceTickInterrupt); 04007 /* After initializing the OS, we may Enter the OS, indicating that we want a task switch and, 04008 * since we come from an interrupt, may need to add a tick. We also tell, if needed if we were 04009 * running an idle task lately. */ 04010 privEnterOS(uiIdleAction | defActionTaskStateSwitch | defActionTickStateTick); } 04011 04012 04013 void main(void) 04014 { /* Interrupts are switched off at entrance. 04015 * Note that the behavior of the stack set up has been changed from gcc4.2.x to 4.3.x. From 04016 * the latter version onwards the stack is only set up before the main. The former version 04017 * did an initialization of the stack twice. Main is now a normal function. We only have to 04018 * make sure the stack is defined at all, but that is done in initialization code which 04019 * calls main. */ 04020 /* All tasks must be set up. */ 04021 Tuint08 uiLoopTask; 04022 /* Usually, there is some hardware related stuff that must be done (setting the pll, 04023 * choosing the main clock etc etc */ 04024 portInit(); 04025 /* If we choose to show the reset, this is the place to call it. Note that we should arrive 04026 * here only once. Usually coming here a second time indicates a major error in your code, 04027 * so it is nice if you got notified. I use it to rapidly blink all leds three times. */ 04028 #if (cfgCheckReset == cfgTrue) 04029 privShowReset(); 04030 #endif 04031 /* If we check the OS stack, we can perform the first check here to see if the stack is not 04032 * under the minimum required value, just to store all background variables. Seems trivial, 04033 * but I got that message several times now. */ 04034 #if (cfgCheckOsStack == cfgTrue) 04035 /* If the OS stack is under the minimum, there is no point in starting the system, thus this 04036 * is made a fatal error. */ 04037 if ((StackSizeOS) < defOsStackMinimum) { privShowError((fatOsStackUnderMinimum | errTaskStateNon), callIdSystem, errNoInfo); } 04038 #endif 04039 /* If present call appBoot code. This is used by the user to perform general initializations. */ 04040 #if (callAppBoot == cfgTrue) 04041 appBoot(); 04042 #endif 04043 /* Create a task control block for every task and set up a new context, as if the task 04044 * already existed before. */ 04045 for (uiLoopTask=0; uiLoopTask<defNumberOfTasks; uiLoopTask++) 04046 { /* Since there is no status as off yet, we must renew it. However, we 04047 * can be pretty sure there are no locks yet. There is no need to 04048 * clean any, there set it to keep. The same holds true for any watermarks. 04049 * In case of inlined code, the compiler knows which peace can be cut out. */ 04050 privTaskInit(uiLoopTask,(defInitContextRenew | defInitStatusCopyDont | defInitSharedPassive | defInitStatusPrioRenew | defInitLockKeep | defInitProcessAll)); 04051 /* Sometimes the user want to do some one time initialization per task, 04052 * this is inside the init routines. Call it if present. Note that the initializations 04053 * are called per task, thus initialization cannot refer to each other.*/ 04054 #if (callAppInit == cfgTrue) 04055 portFlashReadWord(fpInitTask,pxInitlist[uiLoopTask])(); 04056 #endif 04057 } 04058 /* The timer is hardware dependent. The called routine below expects the tick interrupts 04059 * to be setup, but not activated yet. 04060 * The (tick) interrupt model used depends on a lot of parameters. At this point it is needed 04061 * to know that the routines starting a task, idle or sleep state manage the activation of 04062 * the tick interrupt themselves, so we do not need to take care here. */ 04063 portSetupTimerInterrupt(); 04064 /* All preparations are done, we may enter the OS to start the first task. We must really switch 04065 * since it may be possible that no task can be started, and than we must be able to switch to 04066 * idle task directly. */ 04067 privEnterOS(defActionTaskStateSwitch); 04068 /* we never get here */ 04069 } 04070 04071 /* ========================================================================= */ 04072 /* API START =============================================================== */ 04073 /* ========================================================================= */ 04074 04084 /* Gcc does not understand our wrappers, specially it does not understand that 04085 * a function may have a return type, yet it does not possess any instruction 04086 * the returns a value of that type. */ 04087 #pragma GCC diagnostic ignored "-Wreturn-type" 04088 04110 /* Function wrapper for taskDelayFromNow. */ 04111 #if (includeTaskDelayFromNow == cfgTrue) 04112 04113 void taskDelayFromNow(Tuint16 uiTicksToWait) 04114 { portResqueGlobalInterruptState(); 04115 portSaveContext(); 04116 portJump(privDelayFromNowBody); } 04117 04118 #endif 04119 04120 04121 /* Function wrapper for taskDelayFromWake. */ 04122 #if (includeTaskDelayFromWake == cfgTrue) 04123 04124 void taskDelayFromWake(Tuint16 uiTicksToWait) 04125 { portResqueGlobalInterruptState(); 04126 portSaveContext(); 04127 portJump(privDelayFromWakeBody); } 04128 04129 #endif 04130 04131 04132 /* Function wrapper for taskRecreate. */ 04133 #if (includeTaskRecreate == cfgTrue) 04134 04135 void taskRecreate(Tuint08 uiTaskNumber) 04136 { portResqueGlobalInterruptState(); 04137 portSaveContext(); 04138 portJump(privRecreateBody); } 04139 04140 #endif 04141 04142 04143 /* Function wrapper for taskRestart. */ 04144 #if (includeTaskRestart == cfgTrue) 04145 04146 void taskRestart(Tuint08 uiRestartMode, Tuint16 uiTicksToWait) 04147 { portResqueGlobalInterruptState(); 04148 portSaveContext(); 04149 portJump(privRestartBody); 04150 /* TODO This total useless wasted bytes are because gcc does not understand the 04151 * current method does not return, and, and that is worse, there exists no 04152 * pragma to keep its mouth shut. The code of course never gets here. */ 04153 while(true); } 04154 04155 #endif 04156 04157 04158 /* Function wrapper for taskYield. */ 04159 #if (includeTaskYield == cfgTrue) 04160 04161 void taskYield(void) 04162 { portResqueGlobalInterruptState(); 04163 portSaveContext(); 04164 portJump(privYieldBody); } 04165 04166 #endif 04167 04168 04169 /* Function wrapper for taskSuspend. */ 04170 #if (includeTaskSuspend == cfgTrue) 04171 04172 void taskSuspend(Tuint08 uiSuspendMode) 04173 { portResqueGlobalInterruptState(); 04174 portSaveContext(); 04175 portJump(privSuspendBody); } 04176 04177 #endif 04178 04179 04180 /* Function wrapper for taskSleep. */ 04181 #if (cfgUseLowPowerSleep == cfgTrue) && (includeTaskSleep == cfgTrue) 04182 04183 void taskSleep(void) 04184 { portResqueGlobalInterruptState(); 04185 portSaveContext(); 04186 portJump(privSleepBody); } 04187 04188 #endif 04189 04190 /* Function wrapper for taskKill. */ 04191 #if (includeTaskTerminate == cfgTrue) 04192 04193 void taskTerminate(Tuint08 uiTaskNumber) 04194 { portResqueGlobalInterruptState(); 04195 portSaveContext(); 04196 portJump(privTerminateBody); } 04197 04198 #endif 04199 04200 04201 /* Function wrapper for taskSleepAll. */ 04202 #if (cfgUseLowPowerSleep == cfgTrue) && (includeTaskSleepAll == cfgTrue) 04203 04204 void taskSleepAll(void) 04205 { portResqueGlobalInterruptState(); 04206 portSaveContext(); 04207 portJump(privSleepAllBody); } 04208 04209 #endif 04210 04211 04212 /* Function wrapper for taskWaitForTasks. */ 04213 #if (cfgUseSynchronization != cfgSyncNon) && (includeTaskWaitForTasks == cfgTrue) 04214 04215 #if (cfgUseTimeout == cfgTrue) 04216 Tbool taskWaitForTasks(Tuint08 uiSlot, Tuint08 uiNumberOfTasks, Tuint16 uiTicksToWait) 04217 #else 04218 void taskWaitForTasks(Tuint08 uiSlot, Tuint08 uiNumberOfTasks) 04219 #endif 04220 { portResqueGlobalInterruptState(); 04221 portSaveContext(); 04222 portJump(privWaitForTasksBody); } 04223 04224 #endif 04225 04226 04227 /* Function wrapper for taskSyncRequest. */ 04228 #if (cfgUseSynchronization != cfgSyncNon) && ( (includeTaskQueu == cfgTrue) || (includeTaskMutex == cfgTrue) ) 04229 04230 #if (cfgUseTimeout == cfgTrue) 04231 #if (cfgUseSynchronization == cfgSyncDoubleBlock) 04232 Tbool taskSyncRequest(Tuint08 uiSlotSlot, Tsint08 siFreeLeftFilling, Tsint08 siFreeRightFilling, Tuint16 uiTicksToWait) 04233 #else 04234 Tbool taskSyncRequest(Tuint08 uiSlotSlot, Tsint08 siFreeRightFilling, Tuint16 uiTicksToWait) 04235 #endif 04236 #else 04237 #if (cfgUseSynchronization == cfgSyncDoubleBlock) 04238 void taskSyncRequest(Tuint08 uiSlotSlot, Tsint08 siFreeLeftFilling, Tsint08 siFreeRightFilling) 04239 #else 04240 void taskSyncRequest(Tuint08 uiSlotSlot, Tsint08 siFreeRightFilling) 04241 #endif 04242 #endif 04243 { portResqueGlobalInterruptState(); 04244 portSaveContext(); 04245 portJump(privSyncRequestBody); } 04246 04247 #endif 04248 04249 04250 /* Function wrapper for taskSyncRelease. */ 04251 #if (cfgUseSynchronization != cfgSyncNon) && ( (includeTaskQueu == cfgTrue) || (includeTaskMutex == cfgTrue) ) 04252 04253 void taskSyncRelease(Tuint08 uiSlotSlot) 04254 { portResqueGlobalInterruptState(); 04255 portSaveContext(); 04256 portJump(privSyncReleaseBody); } 04257 04258 #endif 04259 04260 /* Function wrapper for taskWaitForFsAccess. */ 04261 #if (cfgUseFileSystem == cfgTrue) 04262 04263 void privWaitForFsAccess(void) 04264 { portResqueGlobalInterruptState(); 04265 portSaveContext(); 04266 portJump(privWaitForFsAccessBody); } 04267 04268 #endif 04269 04270 /* Function wrapper for taskFileOpen. */ 04271 #if (cfgUseFileSystem == cfgTrue) && (includeTaskFileAccess == cfgTrue) 04272 04273 #if (cfgUseTimeout == cfgTrue) 04274 #if (cfgUseFileSystemConcurrentRead == cfgTrue) 04275 Tbool taskFileOpen(Tbool bReadOnly, Tuint16 uiTicksToWait) 04276 #else 04277 Tbool taskFileOpen(Tuint16 uiTicksToWait) 04278 #endif 04279 #else 04280 #if (cfgUseFileSystemConcurrentRead == cfgTrue) 04281 void taskFileOpen(Tbool bReadOnly) 04282 #else 04283 void taskFileOpen(void) 04284 #endif 04285 #endif 04286 { portResqueGlobalInterruptState(); 04287 portSaveContext(); 04288 portJump(privFileOpenBody); } 04289 04290 #endif 04291 04292 /* Function wrapper for taskFileClose. */ 04293 #if (cfgUseFileSystem == cfgTrue) && (includeTaskFileAccess == cfgTrue) 04294 04295 void taskFileClose(void) 04296 { portResqueGlobalInterruptState(); 04297 portSaveContext(); 04298 portJump(privFileCloseBody); } 04299 04300 #endif 04301 04302 /* Function wrapper for taskWaitForEvent. */ 04303 #if (cfgUseEvents == cfgTrue) && (includeTaskWaitForEvents == cfgTrue) 04304 04305 #if (cfgUseTimeout == cfgTrue) 04306 Tbool taskWaitForEvent(Tuint08 uiEvent, Tuint16 uiTicksToWait) 04307 #else 04308 void taskWaitForEvent(Tuint08 uiEvent) 04309 #endif 04310 { portResqueGlobalInterruptState(); 04311 portSaveContext(); 04312 portJump(privWaitForEventBody); } 04313 04314 #endif 04315 04316 04317 #if ( includeTaskStackCheck == cfgTrue ) 04318 04319 Tuint16 taskStackCheck(Tuint08 uiExtraStackSafety) 04320 { /* Arrive here to check the amount of free stack space. We only want (and can, due 04321 * to the required use of background variables) to include this code in case we have 04322 * stack checking activated */ 04323 #if (cfgCheckTaskStack == cfgTrue) 04324 /* To be sure of correct calculation we always work with a 16 bit stack size. */ 04325 Tuint16 uiStackFree; 04326 Taddress pStack; 04327 /* Obtain the stack pointer at this very moment. Note that the call to the function 04328 * taskStackCheck is included, but privGetStack is a macro, so that does not count for 04329 * extra bytes on the stack */ 04330 privGetStack(pStack); 04331 /* The calculation below equals the calculation done in portSaveContext. The call to this function 04332 * adds an other 2 bytes, equaling the amount the tick interrupt would add. The latter actually 04333 * adds four bytes, but the stack calculation itself is done after the temporarily return address 04334 * has been moved from the stack to the OS stack. Thus that matches precisely. The only thing we 04335 * must realize is that the stack must be able to accommodate that extra two bytes for that period. 04336 * However, that fact cannot be circumvented, otherwise no check is possible. The user must always 04337 * add two bytes (or as much a one call takes) to the stack. Compared to this measurement, that is 04338 * somewhere in the code, there will no be an problem, since usually there are registers to be saved 04339 * too. */ 04340 #if (cfgSysStackGrowthUp == cfgTrue) 04341 /* Please do not trust any calculation with respect to cfgSysStackGrowthUp true, since this is 04342 * untested, and therefore most probably incorrect, at the moment */ 04343 #if (cfgCheckTaskStack ==cfgTrue) 04344 if ((pStack + uiExtraStackSafety)> xOS.pxSave.pcStackLimit) 04345 { privShowError((fatTaskStackOverflowed | errTaskStateCurrent) , callIdSystem, errCurrentTask); } 04346 #endif 04347 uiStackFree = xOS.pxSave.pcStackLimit - pStack - StackSafety; 04348 #else 04349 #if (cfgCheckTaskStack ==cfgTrue) 04350 /* Since this is a 16 bit addition/comparison, we do not have any hinder from a 256 bytes boundary. */ 04351 /* TODO: v0.90: We issue a fatal error here because it is not possible to return to this 04352 * place. If it where possible to force a context switch, this problem would not exist, and 04353 * this call would behave like an ordinary stack overflow error. 04354 */ 04355 if (pStack < (xOS.pxSave.pcStackLimit + uiExtraStackSafety)) 04356 { privShowError((fatTaskStackOverflowed | errTaskStateCurrent) , callIdSystem, errCurrentTask); } 04357 #endif 04358 /* We return the amount of free stack contrary to the stack level, because we do not have the 04359 * the total stack size at hand here. It resides inside flash, and it would cost a lot of code 04360 * to obtain that information. Besides that, it would still be an estimate, not the real level.*/ 04361 uiStackFree = pStack- xOS.pxSave.pcStackLimit - StackSafety; 04362 #endif 04363 /* At this point we do not include watermark calculations The reason is twofold. 04364 * (1) As indicated above, it takes a lot of code to find the stack level and it would still 04365 * be an estimated value, whereas the watermarks should represent real measured values. 04366 * (2) Maybe an interrupt is not possible at the point this function is used, that would 04367 * compromise the result even further. */ 04368 return uiStackFree; 04369 #else 04370 /* Without stack checking return 0. Of course the user should remove the function for which is 04371 * no real need, but that may not be practical during development. */ 04372 return 0; 04373 #endif 04374 } 04375 04376 #endif 04377 04378 04379 #if ( includeIsrStackCheck == cfgTrue ) 04380 04381 Tuint16 isrStackCheck(Tuint08 uiExtraStackSafety) 04382 { /* Arrive here to check the amount of free stack space. In this routine we do calculate the watermark 04383 * for isr, see below why. Furthermore it makes no sense to check the isr stack if we let the 04384 * isr make use of the OS stack. */ 04385 #if ((cfgCheckIsrStack == cfgTrue) || (cfgCheckWatermarks == cfgTrue)) && (defUseIsrStack == cfgTrue) 04386 Taddress pStack; 04387 /* Since we allow for large stacks in the isr, we calculate with 16 bit here. */ 04388 Tuint16 uiIsrStackLevel; 04389 /* Obtain the stack pointer at this very moment. Note that the call to the function 04390 * isrStackCheck is included, but privGetStack is a macro, so that does not count for 04391 * extra bytes on the stack */ 04392 privGetStack(pStack); 04393 /* Calculate the present level. */ 04394 #if (cfgSysStackGrowthUp == cfgTrue) 04395 uiIsrStackLevel = ((Tuint16) pStack - (Tuint16) &StackISR[0]); 04396 #else 04397 uiIsrStackLevel = ((Tuint16) &StackISR[(StackSizeISR)-1] - (Tuint16) pStack); 04398 #endif 04399 /* Contrary to the situation in the taskStackCheck routine we do a watermark calculation 04400 * here because 04401 * (1) We do have the total stack size at hand. 04402 * (2) There is no other place to do it. Since we do not expect a context switch, stack information 04403 * is hard to come by */ 04404 #if (cfgCheckWatermarks == cfgTrue) 04405 /* We perform the watermark calculation before the check, since, even if the check returns an error, 04406 * that error may be artificial and this calculation may be valid. */ 04407 if (uiIsrStackMax < uiIsrStackLevel) { uiIsrStackMax = uiIsrStackLevel; } 04408 /* For tasks we have a separate manner to calculate the watermark stack level, and that is 04409 * to check the stack explicitly for bytes that differ from defStackInitByte. The isr stack 04410 * is filled with zeros per default (.bss cleaning) so a similar check would be possible 04411 * here also. Up to now we did not implement it. */ 04412 #endif 04413 #if (cfgCheckIsrStack ==cfgTrue) 04414 /* In the calculation do not take the regular StackSavety into account, That parameter is 04415 * used solely for tasks. Besides, we have two bytes extra anyway. */ 04416 if ((uiIsrStackLevel+uiExtraStackSafety)>(StackSizeISR)) 04417 { privShowError((fatIsrStackOverflowed | errTaskStateNon), callIdSystem, errNoInfo); } 04418 #endif 04419 /* Calculate the free space and return it. */ 04420 return ((Tuint16) (StackSizeISR) - uiIsrStackLevel); 04421 #else 04422 /* Without stack checking return 0. Of course the user should remove the function for which is 04423 * no real need, but that may not be practical during development. */ 04424 return 0; 04425 #endif 04426 } 04427 04428 #endif 04429 04430 04431 #if (includeTaskYield == cfgTrue) 04432 04433 void privYieldBody(void) 04434 { /* Called from user code to switch the task. This is a switching call, let us first initialize the OS. 04435 * (It is a 'body' function too, see the explanation of this design elsewhere.) */ 04436 privInitOsReturn(); 04437 /* The Os is started all delicate information is saved or processed. Let the user know we have 04438 * called the task Yield.*/ 04439 privTraceAPI(callIdTaskYield); 04440 /* task Yield does not require any special functionality. so just start the OS, and ask for a 04441 * task switch. We never return from the call below. */ 04442 privEnterOS(defActionTaskStateSwitch); } 04443 04444 #endif 04445 04446 04447 04448 #if (includeTaskTerminate == cfgTrue) 04449 04450 void privTerminateBody(Tuint08 uiTaskNumber) 04451 { /* Called from user code to terminate a task. Note that this task can only be recreated. 04452 * This is a switching call, let us first initialize the OS. (It is a 'body' function too, 04453 * see the explanation of this design elsewhere.) */ 04454 privInitOsSwitch(); 04455 /* Tell what we are doing */ 04456 privTraceAPI(callIdTaskTerminate); 04457 /* Check if the user uses this method properly. */ 04458 #if (cfgCheckMethodUse == cfgTrue) 04459 /* The usual check to see if the task even exists. Note, since uiTaskNumber is unsigned it can only be to large. */ 04460 if ((uiTaskNumber >= defNumberOfTasks) && (uiTaskNumber != defCurrentTaskNumber)) 04461 /* This is a fatal error, repair your code. */ 04462 { privShowError((fatTaskIllegalTaskNumber | errTaskStateCurrent), callIdTaskTerminate, errCurrentTask ); } 04463 #endif 04464 /* Eliminate defCurrentTaskNumber */ 04465 uiTaskNumber = privTaskNumber(uiTaskNumber); 04466 /* When we kill a task we must be sure that the slot stack is cleaned and maybe blocking tasks 04467 * are released. In other words, it is just like a recreate, but we do not recreate the 04468 * context. Now, since privInit() contains all the cleanup code, it best we call that. It 04469 * also takes care of the situation this task being a shared task. We keep the last priority 04470 * and watermarks so monitors can see that values in their statistics. */ 04471 privTaskInit(uiTaskNumber, (defInitContextKeep | defInitStatusCopyDont | defInitSharedPassive | defInitStatusPrioKeep | defInitLockRelease | defInitProcessAll)); 04472 /* The only thing left to do is to terminate the task */ 04473 TtaskControlBlock * taskTCB = privTcbList(uiTaskNumber); 04474 taskTCB->uiTaskStatus = defBaseTerminatedTask; 04475 /* Done, there is no need to force a switch, unless we killed the current task. However, sorting that out 04476 * cost 12 bytes extra and since this call is not that frequent one extra switch does not really matter. 04477 * We save the bytes. */ 04478 privEnterOS(defActionTaskStateSwitch); } 04479 04480 #endif 04481 04482 04483 #if (includeTaskRecreate == cfgTrue) 04484 04485 void privRecreateBody(Tuint08 uiTaskNumber) 04486 { /* Called from user code to recreate a task. This is a switching call, let us first initialize the OS. 04487 * (It is a 'body' function too, see the explanation of this design elsewhere.) */ 04488 privInitOsSwitch(); 04489 /* Tell what we are doing */ 04490 privTraceAPI(callIdTaskRecreate); 04491 /* Check if the user uses this method properly. */ 04492 #if (cfgCheckMethodUse == cfgTrue) 04493 /* The usual check to see if the task even exists. Note, since uiTaskNumber is unsigned it can only be to large. */ 04494 if ((uiTaskNumber >= defNumberOfTasks) && (uiTaskNumber != defCurrentTaskNumber)) 04495 /* This is a fatal error, repair your code. */ 04496 { privShowError((fatTaskIllegalTaskNumber | errTaskStateCurrent), callIdTaskTerminate, errCurrentTask ); } 04497 #endif 04498 /* Eliminate defCurrentTaskNumber */ 04499 uiTaskNumber = privTaskNumber(uiTaskNumber); 04500 /* Now. re-initialize the task Replace the task status register we do want to reactivate a 04501 * terminated/blocked/delayed task) and reset its priority. Furthermore, if this tasks holds 04502 * any lock, mutex, queue etc these must be properly released. If we recreate a shared task 04503 * then it is first put back in the pool of shared tasks. */ 04504 privTaskInit(uiTaskNumber, (defInitContextRenew | defInitStatusCopyDont | defInitSharedPassive | defInitStatusPrioRenew | defInitLockRelease | defInitProcessAll)); 04505 /* Recreating may require the reinitialization of the hardware, so */ 04506 #if (callAppInit == cfgTrue) 04507 portFlashReadWord(fpInitTask,pxInitlist[uiTaskNumber])(); 04508 #endif 04509 /* Done, activate a new task */ 04510 privEnterOS(defActionTaskStateSwitch); } 04511 04512 #endif 04513 04514 04515 #if (includeTaskRestart == cfgTrue) 04516 04517 void privRestartBody(Tuint08 uiRestartMode, Tuint16 uiTicksToWait) 04518 { /* Called from user code to restart a task. This is a switching call, let us first initialize the OS. 04519 * (It is a 'body' function too, see the explanation of this design elsewhere.) */ 04520 privInitOsSwitch(); 04521 /* Tell what we are doing */ 04522 privTraceAPI(callIdTaskRestart); 04523 /* What is the current task number? */ 04524 Tuint08 uiTaskNumber = privTaskNumber(defCurrentTaskNumber); 04525 /* Check if the user uses this method properly. */ 04526 #if (cfgCheckMethodUse == cfgTrue) 04527 /* Check if have a valid start mode */ 04528 if ( ((uiRestartMode & defBaseRestartSetMask) != 0x00) ) 04529 /* Report that we have an invalid restart mode. */ 04530 { privShowError((errInvalidRestartMode | errTaskStateCurrent | errOsStateAsIs), callIdTaskRestart, errCurrentTask ); } 04531 /* Check the capabilities of the current task */ 04532 privCheckCapabilities(callIdTaskRestart, ((cfgCapDelay) & 0xFF) ); 04533 /* The usual check to see if the waiting time is not to large. The point is, if we make the waiting 04534 * so large that the wakeup ends in the same block as the current time (due to roll over), it 04535 * will be woken almost instantly. This must be prohibited. */ 04536 if (uiTicksToWait > defDelayTimeMax) 04537 /* This is not a fatal error, the task is terminated. */ 04538 { privShowError((errTaskDelayTooLong | errTaskStateCurrent | errOsStateAsIs), callIdTaskRestart, errCurrentTask ); } 04539 /* For certain checks we need the tack control block.*/ 04540 #if (defUseTaskLevels == cfgTrue) || (cfgUseFileSystem == cfgTrue) || (includeTaskProtectSwitchTasks == cfgTrue) || (includeTaskProtectSwitchCritical == cfgTrue) 04541 TtaskControlBlock * taskTCB = privTcbList(uiTaskNumber); 04542 #endif 04543 /* It is an error to restart a task in the dominant mode. */ 04544 #if (includeTaskProtectSwitchTasks == cfgTrue) || (includeTaskProtectSwitchCritical == cfgTrue) 04545 /* See if that is happening */ 04546 if ((taskTCB->uiTaskStatus & defBaseDressGetMask) == defBaseDressRunable) 04547 /* Report an error and stop the task. */ 04548 { privShowError((errIllegalDominantState | errTaskStateCurrent | errOsStateAsIs), callIdTaskRestart, errCurrentTask ); } 04549 #endif 04550 /* If we make use of some nesting, we may not call a restart in the middle of a nesting for one 04551 * of the critical states. */ 04552 #if (defUseTaskLevels == cfgTrue) 04553 if (taskTCB->uiTaskLevels != defTaskLevelsInit) 04554 /* Although an error, it is not a critical one: */ 04555 { privShowError((errTaskNestingPresent | errTaskStateCurrent | errOsStateAsIs), callIdTaskRestart, errCurrentTask ); } 04556 #endif 04557 /* If we make use of the file system, we may not call restart when holding a lock. Note that 04558 * we only check, and always wipe the fields when present. That can have real bad consequences, 04559 * if we were to violate this requirement. */ 04560 #if (cfgUseFileSystem == cfgTrue) 04561 if ( (taskTCB->uiTaskMonitor & (defFsReadGetMask | defFsWriteGetMask)) != (defFsReadClear | defFsWriteClear) ) 04562 /* If we have lock, this may be a fatal error since it will not be possible for other tasks to 04563 * use the file system any more.*/ 04564 { privShowError((errFileOpenMode | errTaskStateCurrent | errOsStateAsIs), callIdTaskRestart, errCurrentTask ); } 04565 #endif 04566 #endif 04567 /* Since an incorrect value can lead to bizarre results we normalize the input, even if it is correct. */ 04568 uiRestartMode = uiRestartMode & defBaseRestartGetMask; 04569 /* Now. re-initialize the task, keeping the essentials from the task, as is. */ 04570 privTaskInit(uiTaskNumber, (uiRestartMode | defInitContextRenew | defInitStatusCopyDo | defInitSharedPassive | defInitStatusPrioKeep | defInitLockKeep | defInitProcessAll)); 04571 /* If needed we can make sure the task is delayed somewhat before it revives. Note that this delay 04572 * is done after the initialization, because the initialization routines wipes delays. */ 04573 if (uiTicksToWait != defDelayTimeZero) { privDelayCalcFromNow(uiTicksToWait); } 04574 /* Done, activate a new task */ 04575 privEnterOS(defActionTaskStateSwitch); } 04576 04577 #endif 04578 04579 04580 #if (includeGenReboot == cfgTrue) 04581 04582 void genReboot(void) 04583 { /* Arrive here is you want a (software) reset of the system. After this is initiated we 04584 * do not want other processes to intervene. Therefore we disable all interrupts. */ 04585 privDisableGlobalInterrupts(); 04586 /* Tell what we are doing */ 04587 privTraceAPI(callIdGenReboot); 04588 /* Do your work. We do not expect to return from this call. */ 04589 portReboot(); } 04590 04591 #endif 04592 04593 04594 04595 #if (includeGenAddtoTickCount == cfgTrue) 04596 04597 void genAddtoTickCount(Tuint16 uiSleepTime) 04598 { /* Call this if you want to shift the tick counter into the future. During this manipulations 04599 * we do not want to be disturbed. These operations take place in the realm (OS, task, isr) 04600 * from which we where called. This is important, it cannot be implemented as a switching call. 04601 * Therefore we must block all interrupts during operation. */ 04602 privEnterSysCritical(); 04603 /* Tell what we are doing */ 04604 privTraceAPI(callIdGenAddtoTickCount); 04605 /* Check if the user uses this method properly. */ 04606 #if (cfgCheckMethodUse == cfgTrue) 04607 /* If we have no protection for the OS from interrupts ... */ 04608 #if (cfgIntOsProtected == cfgFalse) 04609 /* we may not arrive here from an isr */ 04610 if ((uiOsStatus & defContextGetMask) == defContextStateIsr) 04611 /* and if we do this is a fatal error. */ 04612 { privShowError((fatIllegalCallfromISR | errTaskStateNon), callIdGenAddtoTickCount, errNoInfo ); } 04613 #endif 04614 #endif 04615 /* We need the HighByte of the tick counter for later calculations. */ 04616 Tuint08 uxTickCountOldHighByte = uxTickCount.HighByte; 04617 /* Create a new tick counter. The new time is the old time shifted by the given amount. This is 04618 * a 16 bit addition. Missed calls to appTick00() and appTick08() are lost. We assume that the given 04619 * uiSleepTime has a resolution on tick level. If this is not the case, the resulting new time 04620 * may differ from the value that is would have had when no sleeping occurred. */ 04621 Tuint16 uiNewTime = uiSleepTime + uxTickCount.Full; 04622 /* Extract the new High and Low byte.*/ 04623 uxTickCount.Full = uiNewTime; 04624 /* The subbyte is of no importance. In case we come here from a low power sleep, that byte was 04625 * used to store the maximal sleep time in tick blocks. In any case it is beyond the scope of 04626 * this routine to accurately calculate a new value. The SubByte may not exist when cfgUseLowPowerSleep 04627 * is set to false, thus we check. */ 04628 #if (cfgUseLowPowerSleep == cfgTrue) 04629 uxTickCount.SubByte = 0; 04630 #endif 04631 /* Now we must determine the effects of this time shift. There are a couple of situations 04632 * (1) Was so short that we do not need to wake any delay tasks, or do we have to? 04633 * (2) Must we activate the near wake bit in order to signal that some tasks are about 04634 * to be waked up? 04635 * (3) Did we cross the tick counter boundary and must we call appTick16() ? 04636 * In any case we need the number of tick blocks the system did actually sleep, which 04637 * may differ from the high byte of the uiSleepTime. */ 04638 Tuint08 uiSleepPeriod = uxTickCount.HighByte - uxTickCountOldHighByte; 04639 /* First we determine if the tick counter made a full round of 0xFFxx ticks. (more 04640 * is not possible, or at least cannot be detected here. */ 04641 Tbool bFullRound = ((uiSleepTime & 0x8000)!=0) && (uiSleepPeriod==0); 04642 /* If so we must wake all tasks, which is certainly not going to happen when 04643 * uiSleepPeriod equals zero, so turn it into 0xFF. In the situation where 04644 * uiSleepTime < ca 0x100 the uiSleepPeriod remains zero, which is OK since all 04645 * tasks will be woken by the near wake bit. */ 04646 if ( bFullRound ) { uiSleepPeriod--; } 04647 /* See if we had passed the tick boundary. In case of a full round we must have, and 04648 * otherwise this is easily detected by comparing the new and old high bytes of the 04649 * tick counters. Of course, the appTick16() comes probably to late. */ 04650 #if (callAppTick16 == cfgTrue) 04651 if ((uxTickCountOldHighByte>uxTickCount.HighByte) | bFullRound) { appTick16(); } 04652 #endif 04653 /* Releasing delay tasks that should be woken during low power sleep, or even searching for 04654 * such tasks costs quite some code. If you are certain you did not exceed the recommended 04655 * sleeping time in the portSleep() call, there is no need to do all this work. So you may 04656 * choose to exclude it from your code. If, by mistake, you have tasks that should have 04657 * been woken but are not, they remain sleeping until the next round of the tick counter. */ 04658 #if (cfgUseDelay == cfgTrue) && (cfgUseLowPowerDelayRelease == cfgTrue) 04659 Tuint08 uiLoopTask; 04660 /* Ok, lets start searching for tasks that should have woken when the system was in low power 04661 * sleep. We must test each task individually. */ 04662 for (uiLoopTask=0; uiLoopTask<defNumberOfTasks; uiLoopTask++) 04663 { TtaskControlBlock * loopTCB = privTcbList(uiLoopTask); 04664 /* Check if we have a task that is delayed. It need not to be running. */ 04665 if ( (loopTCB->uiTaskStatus & defBaseDelayStateGetMask) == defBaseDelayStateDelayed) 04666 { /* Now we must calculate the delay and see if the activation time was situated 04667 * in the period the device did sleep. Note the uxDelay.HighByte contains 04668 * the moment the task should have been woken. If this subtraction should come 04669 * out negative, then, due to roll over the uiDelayTime gets higher as the 04670 * uiSleepPeriod, thus no wake up is done. */ 04671 Tuint08 uiDelayTime = uxTickCount.HighByte - loopTCB->uxDelay.HighByte; 04672 /* If the delay time equals 0 we must investigate further. The first idea 04673 * would be, nothing should happen. This is because such tasks are to be woken 04674 * by the privIncrementTick() routine, since they could lie slightly 04675 * in the future. We activate the near wake bit so they don't escape the check. 04676 * The only problem with that solution is that it may be the case that the uxTickCount.LowByte 04677 * equals 0xFF, thus due to a tick increment the whole block would be skipped. The other 04678 * point of attention is as both uiDelayTime and uiSleepPeriod are zero. That will not 04679 * be that likely but is possible. In that case we handle according to the being 04680 * zero of the uiDelayTime and not according to the equality of both. The trick is 04681 * to lower uiDelayTime to change 0x00 into 0xFF */ 04682 uiDelayTime --; 04683 /* and skip the equality test. I.e. perform a '<' test rather then '<='. The test never 04684 * passes for equality in case uiDelayTime did equal zero. And we can test 0xFF separately. 04685 * In the latter test we see if the Lowbyte of the delay is before the current time low byte. */ 04686 if ( (uiDelayTime < uiSleepPeriod) || ((uiDelayTime == 0xFF) && (uxTickCount.LowByte >= loopTCB->uxDelay.LowByte)) ) 04687 { /* If more time has passed as the task should delay, it is released. This may be a release due to as 04688 * simple delay or can be a time out on a block. Note that if uiSleepTimeBlocks = 0xFF we get 04689 * uiSleeptime 0xFF this still results in waking up all tasks, which is needed. Most of them 04690 * are waked here, a few can lie less than 0xFF in the future and will be waked by privIncrementTask() */ 04691 privWakeupFromDelay(uiLoopTask,loopTCB); } } } 04692 #endif 04693 /* We must activate the near wake bit for possible tasks to be waked in the near future. If this 04694 * turns out not to be the case, it is not a problem. Let us not check this. */ 04695 uiOsStatus = ((uiOsStatus & defNearWakeStateSetMask) | defNearWakeStatePresent); 04696 /* Reactivate the interrupts and return to the caller. */ 04697 privExitSysCritical(); } 04698 04699 #endif 04700 04701 04702 #if (cfgUseDelay == cfgTrue) && (includeTaskDelayFromNow == cfgTrue) 04703 04704 void privDelayFromNowBody(Tuint16 uiTicksToWait) 04705 { /* Called from user code to pause a task for a certain time, in this case, 04706 * measured from the present value of the tick counter. This is a switching call, 04707 * let us first initialize the OS. 04708 * (It is a 'body' function too, see the explanation of this design elsewhere.) */ 04709 privInitOsSwitch(); 04710 /* Tell what we are doing */ 04711 privTraceAPI(callIdTaskDelayFromNow); 04712 /* Check if the user uses this method properly. */ 04713 #if (cfgCheckMethodUse == cfgTrue) 04714 /* Check the capabilities of the current task */ 04715 privCheckCapabilities(callIdTaskDelayFromNow, ((cfgCapDelay) & 0xFF) ); 04716 /* The usual check to see if the waiting time is not to large. The point is, if we make the waiting 04717 * so large that the wakeup ends in the same block as the current time (due to roll over), it 04718 * will be woken almost instantly. This must be prohibited. */ 04719 if (uiTicksToWait > defDelayTimeMax) 04720 /* This is not a fatal error, the task is terminated. */ 04721 { privShowError((errTaskDelayTooLong | errTaskStateCurrent | errOsStateAsIs), callIdTaskDelayFromNow, errCurrentTask ); } 04722 #endif 04723 /* If the waiting time equals zero, it is effectively a taskYield. Don't call the 04724 * delay for otherwise it may end up delaying one full tick round. Otherwise 04725 * we call the privDelayCalc with the request to measure the delay time from now */ 04726 if (uiTicksToWait != defDelayTimeZero) { privDelayCalcFromNow(uiTicksToWait); } 04727 /* We are done and call for a task switch. */ 04728 privEnterOS(defActionTaskStateSwitch); } 04729 04730 #endif 04731 04732 04733 #if (cfgUseDelay == cfgTrue) && (includeTaskDelayFromWake == cfgTrue) 04734 04735 void privDelayFromWakeBody(Tuint16 uiTicksToWait) 04736 { /* Called from user code to pause a task for a certain time. This is a switching call, let us 04737 * first initialize the OS. (It is a 'body' function too, see the explanation of this design 04738 * elsewhere.) */ 04739 privInitOsSwitch(); 04740 /* Tell what we are doing */ 04741 privTraceAPI(callIdTaskDelayFromWake); 04742 /* Check if the user uses this method properly. */ 04743 #if (cfgCheckMethodUse == cfgTrue) 04744 /* Check the capabilities of the current task */ 04745 privCheckCapabilities(callIdTaskDelayFromWake, ((cfgCapDelay) & 0xFF) ); 04746 /* The usual check to see if the waiting time is not to large. The point is, if we make the waiting 04747 * so large that the wakeup ends in the same block as the current time (due to roll over), it 04748 * will be woken almost instantly. This must be prohibited. */ 04749 if (uiTicksToWait > defDelayTimeMax) 04750 /* This is not a fatal error, the task is terminated. */ 04751 { privShowError((errTaskDelayTooLong | errTaskStateCurrent | errOsStateAsIs), callIdTaskDelayFromWake, errCurrentTask ); } 04752 #endif 04753 /* if the waiting time equals zero, it is effectively a taskYield. Don't call the 04754 * delay for otherwise it may end up delaying one full tick round. Otherwise 04755 * we call the privDelayCalc with the request to measure the delay time from the 04756 * last wakeup time. */ 04757 if (uiTicksToWait != defDelayTimeZero) { privDelayCalcFromWake(uiTicksToWait); } 04758 /* We are done and call for a task switch. */ 04759 privEnterOS(defActionTaskStateSwitch); } 04760 04761 #endif 04762 04763 04764 #if (cfgUseTasknames == cfgTrue) && ((includeGenGetTaskname == cfgTrue) || (includeGenLogTask == cfgTrue)) 04765 04766 Taddress genGetTaskname(Tuint08 uiTaskNumber) 04767 { /* Call this to obtain the (dynamic) task name of the specified task. This task name is 04768 * stored in flash. We assume that no reprogramming is going on while reading. */ 04769 /* Standard protection */ 04770 privEnterSysCritical(); 04771 /* First, tell what we are doing */ 04772 privTraceAPI(callIdGenGetTaskname); 04773 /* Check if the user uses this method properly. */ 04774 #if (cfgCheckMethodUse == cfgTrue) 04775 /* If we have no protection for the OS from interrupts ... */ 04776 #if (cfgIntOsProtected == cfgFalse) 04777 /* we may not arrive here from an isr */ 04778 if ((uiOsStatus & defContextGetMask) == defContextStateIsr) 04779 /* and if we do this is a fatal error. */ 04780 { privShowError((fatIllegalCallfromISR | errTaskStateNon), callIdGenGetTaskname, errNoInfo ); } 04781 #endif 04782 /* The usual check to see if the task even exists. Note, since uiTaskNumber is unsigned it can only be to large. */ 04783 if ((uiTaskNumber >= defNumberOfTasks) && (uiTaskNumber != defCurrentTaskNumber)) 04784 /* This is a fatal error */ 04785 { privShowError((fatTaskIllegalTaskNumber | errTaskStateCurrent), callIdGenGetTaskname, errCurrentTask ); } 04786 #endif 04787 /* Eliminate defCurrentTaskNumber */ 04788 uiTaskNumber = privTaskNumber(uiTaskNumber); 04789 /* Read the address of the first byte using the flash read macro, and return it. Note that this is 04790 * an address in flash, thus read the content appropriately. */ 04791 Taddress Result = portFlashReadStruc(TtaskDefinitionBlock,pxTDBlist[uiTaskNumber],Taddress,pTaskName); 04792 /* We are done. */ 04793 privExitSysCritical(); 04794 return Result; } 04795 04796 #endif 04797 04798 04799 #if (includeGenSuspend == cfgTrue) 04800 04801 void genSuspend(Tuint08 uiTaskNumber) 04802 { /* Call this if you want to suspend a task. Standard protection */ 04803 privEnterSysCritical(); 04804 /* Tell what we are doing */ 04805 privTraceAPI(callIdGenSuspend); 04806 /* Check if the user uses this method properly. */ 04807 #if (cfgCheckMethodUse == cfgTrue) 04808 /* If we have no protection for the OS from interrupts ... */ 04809 #if (cfgIntOsProtected == cfgFalse) 04810 /* we may not arrive here from an isr */ 04811 if ((uiOsStatus & defContextGetMask) == defContextStateIsr) 04812 /* and if we do this is a fatal error. */ 04813 { privShowError((fatIllegalCallfromISR | errTaskStateNon), callIdGenSuspend, errNoInfo ); } 04814 #endif 04815 /* The usual check to see if the task even exists. Note, since uiTaskNumber is unsigned it 04816 * can only be to large. The defCurrentTaskMask is not allowed and automatically excluded with 04817 * this check. We only need to check if it called with the current task number (which 04818 * is also forbidden) */ 04819 if ((uiTaskNumber >= defNumberOfTasks) && (uiTaskNumber != defCurrentTaskNumber)) 04820 /* This is a fatal error */ 04821 { privShowError((fatTaskIllegalTaskNumber | errTaskStateCurrent), callIdGenSuspend, errCurrentTask ); } 04822 #endif 04823 /* Eliminate defCurrentTaskNumber */ 04824 uiTaskNumber = privTaskNumber(uiTaskNumber); 04825 /* Get the task control block of the task at hand. */ 04826 TtaskControlBlock * taskTCB = privTcbList(uiTaskNumber); 04827 /* First check if we have a shared task in shared mode. */ 04828 #if (defUseSharedStack == cfgTrue) 04829 /* That is the only situation that may be suspended directly. */ 04830 if ((taskTCB->uiTaskStatus & defBaseSharedGetMask) == defBaseSharedTask) 04831 /* Change the status information to mark we want suspension of this task. */ 04832 { taskTCB->uiTaskStatus = (taskTCB->uiTaskStatus & defBaseSuspendedSetMask) | defBaseSuspendedTask; } 04833 else 04834 #endif 04835 /* If not, check if the task is running at all. We do not want to suspend a terminated 04836 * or already suspended task. For all these tasks a suspend request must be issued. */ 04837 { if (taskTCB->uiTaskStatus >= defBaseSleepingTask) 04838 /* Change the status information to mark we want suspension of this task. */ 04839 { taskTCB->defSusField = (taskTCB->defSusField & defSusSetMask) | defSusRequest; } } 04840 /* We are done. */ 04841 privExitSysCritical(); } 04842 04843 #endif 04844 04845 04846 #if (includeTaskSuspend == cfgTrue) 04847 04848 void privSuspendBody(Tuint08 uiSuspendMode) 04849 { /* Call this if you want to suspend yourself, This is a switching call, let us first initialize the OS. 04850 * (It is a 'body' function too, see the explanation of this design elsewhere.) */ 04851 privInitOsSwitch(); 04852 /* Tell what we are doing. */ 04853 privTraceAPI(callIdTaskSuspend); 04854 /* Get the task control block of the task that called this routine. */ 04855 TtaskControlBlock * curTCB = privTcbList(privTaskNumber(defCurrentTaskNumber)); 04856 #if (cfgCheckMethodUse == cfgTrue) 04857 /* Check if the call has a valid argument */ 04858 if ( (uiSuspendMode != defSuspendNow) && (uiSuspendMode != defSuspendClear) 04859 /* If we expect suspends from the outside, we have an other possibility */ 04860 #if (includeGenSuspend == cfgTrue) 04861 && (uiSuspendMode != defSuspendCheck) 04862 #endif 04863 ) 04864 /* Issue an invalid mode error. */ 04865 { privShowError((errInvalidSuspendMode | errTaskStateCurrent), callIdTaskSuspend, errCurrentTask ); } 04866 /* If there is the possibility of the dominant mode, see ... */ 04867 #if (includeTaskProtectSwitchTasks == cfgTrue) || (includeTaskProtectSwitchCritical == cfgTrue) 04868 /* ... if we do not have a dominant task at hand */ 04869 if ((curTCB->uiTaskStatus & defBaseDressGetMask) == defBaseDressRunable) 04870 /* Report an error and stop the task. */ 04871 { privShowError((errIllegalDominantState | errTaskStateCurrent | errOsStateAsIs), callIdTaskSuspend, errCurrentTask ); } 04872 #endif 04873 #endif 04874 /* See in what situation we are. Note that the default action is to clear the request, even if 04875 * we do not suspend. If we request for an immediate suspend, or if it has been requested from 04876 * the outside. The latter is only possible by a genSuspend. */ 04877 if ( ((uiSuspendMode & defSuspendNowGetMask) == defSuspendNow) 04878 #if (includeGenSuspend == cfgTrue) 04879 || ( ((uiSuspendMode & defSuspendCheckGetMask) == defSuspendCheck) && 04880 ((curTCB->defSusField & defSusGetMask) == defSusRequest) ) 04881 #endif 04882 ) 04883 { /* issue the suspend. We do not have to check whether we are sleeping or terminated because that is not 04884 * possible right here, the task called it on itself remember? The same holds for the blocking 04885 * state. Thus just put the task in the suspended state. */ 04886 curTCB->uiTaskStatus = (curTCB->uiTaskStatus & defBaseSuspendedSetMask) | defBaseSuspendedTask; } 04887 /* If the suspend could have been issued from the outside ... */ 04888 #if (includeGenSuspend == cfgTrue) 04889 /* ... clear the request, if present. */ 04890 curTCB->defSusField = (curTCB->defSusField & defSusSetMask) | defSusClear; 04891 #endif 04892 /* We are done, go get a task switch */ 04893 privEnterOS(defActionTaskStateSwitch); } 04894 04895 #endif 04896 04897 04898 #if (includeGenResume == cfgTrue) 04899 04900 void genResume(Tuint08 uiTaskNumber) 04901 { /* Call this to resume a task previously suspended. Standard protection */ 04902 privEnterSysCritical(); 04903 /* Tell what we are doing. */ 04904 privTraceAPI(callIdGenResume); 04905 /* Check if the user uses this method properly. */ 04906 #if (cfgCheckMethodUse == cfgTrue) 04907 /* If we have no protection for the OS from interrupts ... */ 04908 #if (cfgIntOsProtected == cfgFalse) 04909 /* we may not arrive here from an isr */ 04910 if ((uiOsStatus & defContextGetMask) == defContextStateIsr) 04911 /* and if we do this is a fatal error. */ 04912 { privShowError((fatIllegalCallfromISR | errTaskStateNon), callIdGenResume, errNoInfo ); } 04913 #endif 04914 /* The usual check to see if the task even exists. Note, since uiTaskNumber is unsigned it can only be to large. */ 04915 if ((uiTaskNumber >= defNumberOfTasks) && (uiTaskNumber != defCurrentTaskNumber)) 04916 /* This is a fatal error */ 04917 { privShowError((fatTaskIllegalTaskNumber | errTaskStateCurrent), callIdGenResume, errCurrentTask ); } 04918 #endif 04919 /* Eliminate defCurrentTaskNumber */ 04920 uiTaskNumber = privTaskNumber(uiTaskNumber); 04921 /* Get the task control block of the task at hand. */ 04922 TtaskControlBlock * taskTCB = privTcbList(uiTaskNumber); 04923 /* First check if the task is suspended at all. We do not want to resume a terminated or sleeping 04924 * task. In other words we can only resume a suspended task. If we call resume on ourself we 04925 * will not pass this test either. */ 04926 if ( (taskTCB->uiTaskStatus & defBaseSuspendedGetMask) == defBaseSuspendedTask ) 04927 { /* Since only a running task (may be delayed though) or a shared task can be suspended 04928 * we know in which state we must put it at resuming. This cannot be blocked in whatever 04929 * way. It may only be delayed. 04930 * Check if we make use of shared tasks. If so we must see if we are dealing with a shared task.*/ 04931 #if (defUseSharedStack == cfgTrue) 04932 /* Even if all tasks are shared, we must still check if the task is in the shared 04933 * state, since we could be calling this from an interrupt, thereby hitting a scheduled 04934 * shared resumed state, thus, from the stack level we can see if we are dealing 04935 * with a shared stack that should be in the shared state. */ 04936 if (taskTCB->pcStackLevel == defStackEmpty) 04937 { /* We arrive here if we have indeed a task with shared stack in the shared state. 04938 * So we must put it back to the share state instead of a normal one. We only 04939 * need to flip the defBaseStopStateGo bit, since the state is suspended, 04940 * then we end up in the shared state. */ 04941 taskTCB->uiTaskStatus = (taskTCB->uiTaskStatus & (defBaseSharedSetMask)) | (defBaseSharedTask); } 04942 else 04943 #endif 04944 { /* This is not a shared task, so we can resume as normal. */ 04945 taskTCB->uiTaskStatus = (taskTCB->uiTaskStatus & defBaseNoBlocksSetMask) | defBaseNoBlocksTask; } 04946 /* If we are keeping track of exact wakeup times, this is one of the places that 04947 * must be done. */ 04948 #if (cfgUseDelay == cfgTrue) && (cfgUseCorrectWakeupTimes == cfgTrue) 04949 /* Of course we only need to change the wakeup time if we are really waking the task up. If the 04950 * task is still delayed, resuming does not change its delay status, and the task remains 04951 * effectively inactive.*/ 04952 if ((taskTCB->uiTaskStatus & defBaseDelayStateGetMask) == defBaseDelayStateDelayed) 04953 /* The last wakeup time is kept in the uxDelay field. */ 04954 { taskTCB->uxDelay.Full = uxTickCount.Full; } 04955 #endif 04956 /* DISCUSSION 04957 * Resuming a task which was blocked while being suspended may lead to the situation that 04958 * that task will never be resumed again. We could introduce code that tracks that situation 04959 * down and calls privReleaseSyncBlockingTasks(). However, that will at the least costs a lot 04960 * of stack space, or requires an extra messaging system to the OS. In practice it is very 04961 * unwise to suspend a task which is blocking or holds queue's or mutexes. This isues have 04962 * now been resolved by the cooperation model for suspending tasks with the suspend request. 04963 */ 04964 } 04965 /* We clear any standing suspend requests, so that we can be certain that a resumed task 04966 * will not directly be suspended after this call due to a prior genSuspend call. */ 04967 taskTCB->defSusField = (taskTCB->defSusField & defSusSetMask) | defSusClear; 04968 /* We are done. */ 04969 privExitSysCritical(); } 04970 04971 #endif 04972 04973 04974 #if (cfgUseLowPowerSleep == cfgTrue) && (includeTaskSleep == cfgTrue) 04975 04976 void privSleepBody(void) 04977 { /* Call this if you want to put a task to sleep, This is a switching call, let us first initialize the OS. 04978 * (It is a 'body' function too, see the explanation of this design elsewhere.) */ 04979 privInitOsSwitch(); 04980 /* Tell what we are doing. */ 04981 privTraceAPI(callIdTaskSleep); 04982 /* Get the current task number */ 04983 Tuint08 uiTaskNumber = privTaskNumber(defCurrentTaskNumber); 04984 /* Get the task control block of the task that called this routine. */ 04985 TtaskControlBlock * curTCB = privTcbList(uiTaskNumber); 04986 /* Check if the user uses this method properly. */ 04987 #if (cfgCheckMethodUse == cfgTrue) 04988 /* It is an error to call this method if you are writing to the file system (since you 04989 * cannot call this if you are blocked there is no issue with read/write blocking). You 04990 * may call it if you have read access, but note that this may block any write operation 04991 * until the next wake up.*/ 04992 #if (cfgUseFileSystem == cfgTrue) 04993 /* This if the task holds a writelock. */ 04994 if ( (curTCB->defFsField & defFsWriteGetMask) == defFsWriteActive) 04995 /* Report an error and stop the task. */ 04996 { privShowError((errFileWrongMode | errTaskStateCurrent | errOsStateAsIs), callIdTaskSleep, errCurrentTask ); } 04997 #endif 04998 #endif 04999 /* It is not allowed to call this function when you are holding a write lock. 05000 * We do not have to check whether we are suspended or terminated because that is not 05001 * possible right here, the task called it on itself remember? 05002 * Thus put the task in the sleep state directly. */ 05003 /* What is the current task number? */ 05004 #if (defUseSharedStack == cfgTrue) 05005 /* Now. re-initialize shared tasks, keeping the essentials from the task, as is. */ 05006 privTaskInit(uiTaskNumber, (defRestartRunning | defInitContextRenew | defInitStatusCopyDo | defInitSharedPassive | defInitStatusPrioKeep | defInitLockKeep | defInitProcessSharedOnly)); 05007 #endif 05008 /* Put the task to sleep*/ 05009 curTCB->uiTaskStatus = (curTCB->uiTaskStatus & defBaseSleepingSetMask) | defBaseSleepingTask; 05010 /* We are done, go get a task switch */ 05011 privEnterOS(defActionTaskStateSwitch); } 05012 05013 #endif 05014 05015 05016 #if (cfgUseLowPowerSleep == cfgTrue) && (includeTaskSleepAll == cfgTrue) 05017 05018 void privSleepAllBody(void) 05019 { /* Call this if you want to put all tasks to sleep. Note that all tasks are put to 05020 * sleep directly this may not be the optimal point in their execution. 05021 * This is a switching call, let us first initialize the OS. 05022 * (It is a 'body' function too, see the explanation of this design elsewhere.) */ 05023 privInitOsSwitch(); 05024 /* Tell what we are doing. */ 05025 privTraceAPI(callIdTaskSleepAll); 05026 /* If a file system is present we must request for sleep. */ 05027 #if (cfgUseFileSystem == cfgTrue) 05028 /* Indicate to the fs that we want to go to sleep, so it can finish fs operations. */ 05029 uiFsStatus = (uiFsStatus & defFsSleepRequestSetMask) | defFsSleepRequestActive; 05030 #endif 05031 /* Put all tasks to sleep that are egiable. */ 05032 privPutAllTasksToSleep(); 05033 /* We are done., we may have put ourself to sleep, so switch in any case. */ 05034 privEnterOS(defActionTaskStateSwitch); } 05035 05036 #endif 05037 05038 05039 #if (includeTaskProtectSwitchTasks == cfgTrue) || ((includeTaskProtectSwitchCritical == cfgTrue) && (cfgUseNestedCriticals == cfgFalse) ) 05040 05041 void taskDisableSwitchTask(void) 05042 { /* Call this if you want to have explicit control over the system. Tick interrupts keep coming, but the 05043 * switching of tasks are blocked. Note that your task must explicitly unblock this again, otherwise 05044 * all tasks get 'stuck' since they are never scheduled again. Standard protection */ 05045 privEnterSysCritical(); 05046 /* Tell what we are doing. */ 05047 privTraceAPI(callIdTaskDisableSwitchTask); 05048 /* Get the task control block of the task at hand. */ 05049 TtaskControlBlock * curTCB = privTcbList(privTaskNumber(defCurrentTaskNumber)); 05050 /* Setting the dressing to 'runnable' prohibits the scheduling of an other task. */ 05051 curTCB->uiTaskStatus = (curTCB->uiTaskStatus & defBaseDressSetMask) | defBaseDressRunable; 05052 /* Done, such a short routine! */ 05053 privExitSysCritical(); } 05054 05055 void taskEnableSwitchTask(void) 05056 { /* Call this if you want to have explicit control over the system. Call this after a block of task 05057 * switching. Note that your task must explicitly unblock again, otherwise 05058 * all tasks get 'stuck' since they are never scheduled again. Standard protection */ 05059 privEnterSysCritical(); 05060 /* Tell what we are doing. */ 05061 privTraceAPI(callIdTaskEnableSwitchTask); 05062 /* Get the task control block of the task at hand. */ 05063 TtaskControlBlock * curTCB = privTcbList(privTaskNumber(defCurrentTaskNumber)); 05064 /* Setting the dressing to 'done' enables the scheduling of an other task. */ 05065 curTCB->uiTaskStatus = (curTCB->uiTaskStatus & defBaseDressSetMask) | defBaseDressDone; 05066 /* Done, such a short routine! */ 05067 privExitSysCritical(); } 05068 05069 #endif 05070 05071 05072 #if (includeGenSetPriority == cfgTrue) 05073 05074 void genSetPriority(Tuint08 uiTaskNumber, Tuint08 uiNewPriority) 05075 { /* Call this if you want to change the priority of a task. Standard protection */ 05076 privEnterSysCritical(); 05077 /* Tell what we are doing. */ 05078 privTraceAPI(callIdGenSetPriority); 05079 /* Check if the user uses this method properly. */ 05080 #if (cfgCheckMethodUse == cfgTrue) 05081 /* If we have no protection for the OS from interrupts ... */ 05082 #if (cfgIntOsProtected == cfgFalse) 05083 /* we may not arrive here from an isr */ 05084 if ((uiOsStatus & defContextGetMask) == defContextStateIsr) 05085 /* and if we do this is a fatal error. */ 05086 { privShowError((fatIllegalCallfromISR | errTaskStateNon), callIdGenSetPriority, errNoInfo ); } 05087 #endif 05088 /* The usual check to see if the task even exists. Note, since uiTaskNumber is unsigned it can only be to large. */ 05089 if ((uiTaskNumber >= defNumberOfTasks) && (uiTaskNumber != defCurrentTaskNumber)) 05090 /* This is a fatal error */ 05091 { privShowError((fatTaskIllegalTaskNumber | errTaskStateCurrent), callIdGenSetPriority, errCurrentTask ); } 05092 /* Check to see if the priority is not to high. */ 05093 if (uiNewPriority >= defNumberOfPriorities) 05094 /* It suffices to stop this task. */ 05095 { privShowError((errTaskPriorityTooHigh | errTaskStateCurrent), callIdGenSetPriority, errCurrentTask ); } 05096 #endif 05097 /* Eliminate defCurrentTaskNumber */ 05098 uiTaskNumber = privTaskNumber(uiTaskNumber); 05099 /* Get the task control block of the task at hand. */ 05100 TtaskControlBlock * taskTCB = privTcbList(uiTaskNumber); 05101 /* Set the new priority, the three bits are in the status register */ 05102 taskTCB->uiTaskStatus = (taskTCB->uiTaskStatus & defBasePrioSetMask) | ((uiNewPriority << defBasePrioShift) & defBasePrioGetMask); 05103 /* We are done */ 05104 privExitSysCritical(); } 05105 05106 #endif 05107 05108 05109 #if (includeGenGetPriority == cfgTrue) 05110 05111 Tuint08 genGetPriority(Tuint08 uiTaskNumber) 05112 { /* Call this if you want to know the priority of a task. */ 05113 Tuint08 Result; 05114 /* Don't allow for changes in the background. Standard protection */ 05115 privEnterSysCritical(); 05116 /* Tell what we are doing. */ 05117 privTraceAPI(callIdGenGetPriority); 05118 /* Check if the user uses this method properly. */ 05119 #if (cfgCheckMethodUse == cfgTrue) 05120 /* If we have no protection for the OS from interrupts ... */ 05121 #if (cfgIntOsProtected == cfgFalse) 05122 /* we may not arrive here from an isr */ 05123 if ((uiOsStatus & defContextGetMask) == defContextStateIsr) 05124 /* and if we do this is a fatal error. */ 05125 { privShowError((fatIllegalCallfromISR | errTaskStateNon), callIdGenGetPriority, errNoInfo ); } 05126 #endif 05127 /* The usual check to see if the task even exists. Note, since uiTaskNumber is unsigned it can only be to large. */ 05128 if ((uiTaskNumber >= defNumberOfTasks) && (uiTaskNumber != defCurrentTaskNumber)) 05129 /* This is a fatal error */ 05130 { privShowError((fatTaskIllegalTaskNumber | errTaskStateCurrent), callIdGenGetPriority, errCurrentTask ); } 05131 #endif 05132 /* Eliminate defCurrentTaskNumber */ 05133 uiTaskNumber = privTaskNumber(uiTaskNumber); 05134 /* Extract the priority, the three bits are in the status register */ 05135 Result = (privTcbList(uiTaskNumber)->uiTaskStatus & defBasePrioGetMask) >> defBasePrioShift ; 05136 /* We are done */ 05137 privExitSysCritical(); 05138 return Result; } 05139 05140 #endif 05141 05142 05143 #if (includeGenGetTickCount == cfgTrue) 05144 05145 Tuint16 genGetTickCount(void) 05146 { /* Call this if you want to know the value of the tick counter. */ 05147 Tuint16 Result; 05148 /* Only inside the OS the tick counter can be changed. Standard protection */ 05149 privEnterSysCritical(); 05150 /* Tell what we are doing. */ 05151 privTraceAPI(callIdGenGetTickCount); 05152 /* Check if the user uses this method properly. */ 05153 #if (cfgCheckMethodUse == cfgTrue) 05154 /* If we have no protection for the OS from interrupts ... */ 05155 #if (cfgIntOsProtected == cfgFalse) 05156 /* we may not arrive here from an isr */ 05157 if ((uiOsStatus & defContextGetMask) == defContextStateIsr) 05158 /* and if we do this is a fatal error. */ 05159 { privShowError((fatIllegalCallfromISR | errTaskStateNon), callIdGenGetTickCount, errNoInfo ); } 05160 #endif 05161 #endif 05162 /* Construct the tick counter. You may ask yourself what value you get if you call this from 05163 * an interrupt isr that came just on the moment the low byte of the tick counter was updated 05164 * and the high byte was still old. Well, this is not allowed. Or interrupts are allowed during 05165 * OS execution, but then you may not call genXXX routines, or you may call them, but then 05166 * you must have protection on. */ 05167 Result = uxTickCount.Full; 05168 /* Done. */ 05169 privExitSysCritical(); 05170 return Result; } 05171 05172 #endif 05173 05174 05175 #if (defUseDelay == cfgTrue) && (includeGenGetLastWakeTime == cfgTrue) 05176 05177 Tuint16 genGetLastWakeTime(Tuint08 uiTaskNumber) 05178 { /* Sometimes it may be useful to know what was the last time a particular task was waked. 05179 * use this method to obtain that information. */ 05180 Tuint16 Result; 05181 /* Since this time can be influenced by the OS we want to protect it from that. 05182 * Standard protection */ 05183 privEnterSysCritical(); 05184 /* Tell what we are doing. */ 05185 privTraceAPI(callIdGenGetLastWakeTime); 05186 /* Check if the user uses this method properly. */ 05187 #if (cfgCheckMethodUse == cfgTrue) 05188 /* If we have no protection for the OS from interrupts ... */ 05189 #if (cfgIntOsProtected == cfgFalse) 05190 /* we may not arrive here from an isr */ 05191 if ((uiOsStatus & defContextGetMask) == defContextStateIsr) 05192 /* and if we do this is a fatal error. */ 05193 { privShowError((fatIllegalCallfromISR | errTaskStateNon), callIdGenGetLastWakeTime, errNoInfo ); } 05194 #endif 05195 /* The usual check to see if the task even exists. Note, since uiTaskNumber is unsigned it can only be to large. */ 05196 if ((uiTaskNumber >= defNumberOfTasks) && (uiTaskNumber != defCurrentTaskNumber)) 05197 /* This is a fatal error */ 05198 { privShowError((fatTaskIllegalTaskNumber | errTaskStateCurrent), callIdGenGetLastWakeTime, errCurrentTask ); } 05199 /* We should check the capabilities of the given task. Note that the current task may not need to possess 05200 * delay capabilities. The question is of course, which of the tasks is in error? The current one for asking 05201 * capabilities the targeted one does not possess, or the targeted one, for not possessing the 05202 * capability to respond. Actually, i think it is the current task, since terminating the targeting 05203 * task does not change anything in his favor. This error may come over and over again. 05204 * We do not have the means to check this without a lot of extra code, so the best thing to do 05205 * is to skip this. */ 05206 #endif 05207 /* Eliminate defCurrentTaskNumber */ 05208 uiTaskNumber = privTaskNumber(uiTaskNumber); 05209 /* Get the task control block of the task at hand. */ 05210 TtaskControlBlock * taskTCB = privTcbList(uiTaskNumber); 05211 /* Construct the last wake time */ 05212 Result = taskTCB->uxDelay.Full; 05213 privExitSysCritical(); 05214 /* Done, return the result, which, because we tick counters are allowed again may already be outdated. */ 05215 return Result; } 05216 05217 #endif 05218 05219 05220 #if (cfgUseTaskWatchdog == cfgTrue) && (includeTaskFeedWatchdog == cfgTrue) 05221 05222 void taskFeedWatchdog(void) 05223 { /* Call this regularly to keep the watchdog silent. Standard protection */ 05224 privEnterSysCritical(); 05225 /* Tell what we are doing. */ 05226 privTraceAPI(callIdTaskFeedWatchdog); 05227 /* Check if the user uses this method properly. */ 05228 #if (cfgCheckMethodUse == cfgTrue) 05229 /* Check the capabilities of the given task. */ 05230 privCheckCapabilities(callIdTaskFeedWatchdog, ((cfgCapWatchdog) & 0xFF) ); 05231 #endif 05232 /* What task where we in? */ 05233 TtaskControlBlock * curTCB = privTcbList(privTaskNumber(defCurrentTaskNumber)); 05234 /* reset the watchdog counter (2 bit) to sleep. */ 05235 curTCB->defDogField = (curTCB->defDogField & defDogSetMask) | defDogSleep ; 05236 /* Done */ 05237 privExitSysCritical(); } 05238 05239 #endif 05240 05241 05242 #if (cfgUseTaskWatchdog == cfgTrue) && (includeTaskKillWatchdog == cfgTrue) 05243 05244 void taskKillWatchdog(void) 05245 { /* Call this to silence the watchdog definitely. Standard protection */ 05246 privEnterSysCritical(); 05247 /* Tell what we are doing. */ 05248 privTraceAPI(callIdTaskKillWatchdog); 05249 /* Check if the user uses this method properly. */ 05250 #if (cfgCheckMethodUse == cfgTrue) 05251 /* Check the capabilities of the given task. */ 05252 privCheckCapabilities(callIdTaskKillWatchdog, ((cfgCapWatchdog) & 0xFF) ); 05253 #endif 05254 /* What task where we in? */ 05255 TtaskControlBlock * curTCB = privTcbList(privTaskNumber(defCurrentTaskNumber)); 05256 /* reset the watchdog counter (2 bit) to dead (zero). */ 05257 curTCB->defDogField = (curTCB->defDogField & defDogSetMask) | defDogDead ; 05258 /* Done */ 05259 privExitSysCritical(); } 05260 05261 #endif 05262 05263 05264 #if ((includeGenLogTask == cfgTrue) || (includeGenLogOs == cfgTrue)) && (includeGenPipeInt16 == cfgFalse) 05265 /* We make this method static is there is no external need, so it can be inlined. */ 05266 static 05267 #endif 05268 /* take care the definition below is coupled to the static above */ 05269 #if ((includeGenLogTask == cfgTrue) || (includeGenLogOs == cfgTrue)) || (includeGenPipeInt16 == cfgTrue) 05270 void genPipeInt16(Tuint16 uiValue, void (*pipe)(Tchar)) 05271 { /* Easy method to push a 16 bit number through a pipe. Big endian, most significant byte first. */ 05272 pipe((Tuint08)(uiValue>>8)); 05273 /* The second byte is found through truncation. */ 05274 pipe((Tuint08)uiValue); } 05275 #endif 05276 05277 #if ((includeGenLogTask == cfgTrue) || (includeGenLogOs == cfgTrue)) && (includeGenPassFlashString == cfgFalse) 05278 /* We make this method static is there is no external need, so it can be inlined. */ 05279 static 05280 #endif 05281 /* take care the definition below is coupled to the static above */ 05282 #if ((includeGenLogTask == cfgTrue) || (includeGenLogOs == cfgTrue)) || (includeGenPassFlashString == cfgTrue) 05283 void genPassFlashString(Taddress pString, Tuint08 uiLength, Tchar cFilling, void (*pipe)(Tchar)) 05284 { /* Easy method to push a string in flash trough a pipe. This method can be extremely stack hungry. 05285 * There are several option for use. If we specify uiLength==0 the whole string will be pushed until 05286 * (but not including) the null character. If we specify a positive length, that will be the precise number 05287 * of characters passed. 05288 * Tell what we are doing */ 05289 privTraceAPI(callIdGenPassFlashString); 05290 /* This counter counts characters pushed */ 05291 Tuint08 uiCharCount = 0; 05292 /* We must remember if the number specified was zero 05293 * TODO This can be solved much more efficiently, */ 05294 Tbool bFixedLength = (uiLength != 0); 05295 Tchar cChar = (Tchar) (Tuint08) (Tuint16) pString; 05296 /* Sending 0 means sending all (max 255 characters)*/ 05297 uiLength--; 05298 for (uiCharCount = 0; uiCharCount<=uiLength; uiCharCount++) 05299 { if (cChar != 0) { cChar = portFlashReadByte(Tchar, pString[uiCharCount]); } 05300 if (cChar != 0) { pipe(cChar); } else if (bFixedLength) { pipe(cFilling); } else break; } } 05301 #endif 05302 05303 #if (includeGenLogOs == cfgTrue) 05304 05305 void genLogOs(void (*pipe)(Tchar)) 05306 { /* Push the information of the OS through the pipe. This is the structure of information to be expected: 05307 * [Id(1)] [StatusOs(1)] [StatusFs(1)] [LoadOs(2)] [LoadIdle(2)] [LoadIsr(2)] [StackOsMax(1)] [StackIsrMax(2)] 05308 * The number of bytes is constant: 12, if some information is not available, null is send. */ 05309 #if (cfgCheckTrace == cfgTrue) || (cfgCheckMethodUse == cfgTrue) 05310 /* We need protection for the maintenance functions. */ 05311 privEnterSysCritical(); 05312 #endif 05313 /* Tell what we are doing */ 05314 privTraceAPI(callIdGenLogOs); 05315 /* Check if the user uses this method properly. */ 05316 #if (cfgCheckMethodUse == cfgTrue) 05317 /* If we have no protection for the OS from interrupts ... */ 05318 #if (cfgIntOsProtected == cfgFalse) 05319 /* we may not arrive here from an isr */ 05320 if ((uiOsStatus & defContextGetMask) == defContextStateIsr) 05321 /* and if we do this is a fatal error. */ 05322 { privShowError((fatIllegalCallfromISR | errTaskStateNon), callIdGenLogOs, errNoInfo ); } 05323 #endif 05324 #endif 05325 #if (cfgCheckTrace == cfgTrue) || (cfgCheckMethodUse == cfgTrue) 05326 /* Here we can switch of that protection */ 05327 privExitSysCritical(); 05328 #endif 05329 /* Tell we are ready to send the OS information*/ 05330 pipe(defResponseLogOs); 05331 /* The Status information: [][][][] [current task(4)]*/ 05332 pipe(uiOsStatus); 05333 #if (cfgUseFileSystem == cfgTrue) 05334 pipe(uiFsStatus); 05335 #else 05336 pipe(0); 05337 #endif 05338 /* The load of the OS, i.e. the number of subticks passed in the OS realm, if this information 05339 * is not available, send zero. */ 05340 #if (cfgUseLoadMonitor == cfgTrue) 05341 genPipeInt16(uiOsLoadTotal,pipe); 05342 #else 05343 genPipeInt16(0,pipe); 05344 #endif 05345 /* The load of the Idle task, i.e. the number of subticks passed as idle, if this information 05346 * is not available, send zero. */ 05347 #if (cfgUseLoadMonitor == cfgTrue) 05348 genPipeInt16(uiIdleLoadTotal,pipe); 05349 #else 05350 genPipeInt16(0,pipe); 05351 #endif 05352 /* The load of the ISR, i.e. the number of subticks passed in the isr, if this information 05353 * is not available, send zero. */ 05354 #if (cfgUseLoadMonitor == cfgTrue) && (cfgIntUserDefined == cfgTrue) 05355 genPipeInt16(uiIsrLoadTotal,pipe); 05356 #else 05357 genPipeInt16(0,pipe); 05358 #endif 05359 /* If we are keeping watermarks, we pass the OS stack level */ 05360 #if (cfgCheckWatermarks == cfgTrue) 05361 pipe(uiOsStackMax); 05362 #else 05363 pipe(0); 05364 #endif 05365 /* and possibly the amount of stack used by the isr. */ 05366 #if (cfgCheckWatermarks == cfgTrue) && (defUseIsrStack == cfgTrue) 05367 genPipeInt16(uiIsrStackMax,pipe); 05368 #else 05369 genPipeInt16(0,pipe); 05370 #endif 05371 /* Done*/ 05372 } 05373 #endif 05374 05375 05376 #if (includeGenLogTask == cfgTrue) 05377 05378 void genLogTask(Tuint08 uiTaskNumber, void (*pipe)(Tchar)) 05379 { /* Push the information of one of the tasks through the pipe. This is the structure of information to be expected: 05380 * [Id(1)] [TaskNr(1)] [Status(1)] [LoadOs/0(2)] [Name(8)] [TaskMonitor(1)] [TaskLevels(2)] [SlotStack[4]] [StackMax(2)] [RegUse(1)] 05381 * The number of bytes is constant: 23, if some information is not available, null is send. */ 05382 /* Tell what we are doing */ 05383 #if (cfgCheckTrace == cfgTrue) || (cfgCheckMethodUse == cfgTrue) 05384 /* We need protection for the maintenance functions. */ 05385 privEnterSysCritical(); 05386 #endif 05387 privTraceAPI(callIdGenLogTask); 05388 /* Check if the user uses this method properly. */ 05389 #if (cfgCheckMethodUse == cfgTrue) 05390 /* If we have no protection for the OS from interrupts ... */ 05391 #if (cfgIntOsProtected == cfgFalse) 05392 /* we may not arrive here from an isr */ 05393 if ((uiOsStatus & defContextGetMask) == defContextStateIsr) 05394 /* and if we do this is a fatal error. */ 05395 { privShowError((fatIllegalCallfromISR | errTaskStateNon), callIdGenLogTask, errNoInfo ); } 05396 #endif 05397 /* The usual check to see if the task even exists. Note, since uiTaskNumber is unsigned it can only be to large. */ 05398 if ((uiTaskNumber >= defNumberOfTasks) && (uiTaskNumber != defCurrentTaskNumber)) 05399 { privShowError((fatTaskIllegalTaskNumber | errTaskStateCurrent), callIdGenLogTask, errCurrentTask ); } 05400 #endif 05401 #if (cfgCheckTrace == cfgTrue) || (cfgCheckMethodUse == cfgTrue) 05402 /* Here we can switch of that protection */ 05403 privExitSysCritical(); 05404 #endif 05405 /* Eliminate defCurrentTaskNumber */ 05406 uiTaskNumber = privTaskNumber(uiTaskNumber); 05407 /* Get the tcb */ 05408 TtaskExtendedControlBlock * taskTCB = (TtaskExtendedControlBlock *) privTcbList(uiTaskNumber); 05409 Tuint08 uiTaskStatus = taskTCB->uiTaskStatus; 05410 /* Tell we are ready to send the task information*/ 05411 pipe(defResponseLogTask); 05412 /* Start to send the task number */ 05413 pipe(uiTaskNumber); 05414 /* Send the status, this contains the run status, and the priority */ 05415 pipe(uiTaskStatus); 05416 /* If we collected the load information, pass it on */ 05417 #if (cfgUseLoadMonitor == cfgTrue) 05418 genPipeInt16(taskTCB->uiLoadTotal,pipe); 05419 #else 05420 genPipeInt16(0,pipe); 05421 #endif 05422 /* If the dynamical task names are includes, send them. */ 05423 #if (cfgUseTasknames == cfgTrue) 05424 genPassFlashString(genGetTaskname(uiTaskNumber),8,' ',pipe); 05425 #else 05426 genPassFlashString(0,8,' ',pipe); 05427 #endif 05428 /* Send this to report the critical nesting and the watchdog state */ 05429 #if (defUseTaskMonitor == cfgTrue) 05430 pipe(taskTCB->uiTaskMonitor); 05431 #else 05432 pipe(0); 05433 #endif 05434 /* Send the depth of the global, switch and tick critical levels, and their format (only the values 05435 * for Glob and Tick width need to be transmitted, the Switch is the rest (even if it is not used) */ 05436 #if (defUseTaskLevels == cfgTrue) 05437 pipe((defNumTickWidth << 4) | (defNumGlobWidth) ); 05438 pipe(taskTCB->uiTaskLevels); 05439 #else 05440 genPipeInt16(0,pipe); 05441 #endif 05442 /* below we send which slots are used. We only send the first six slots, even if we 05443 * should make use of more. */ 05444 #if (defUseTaskSlot == cfgTrue) 05445 Tuint08 uiSlotSize; 05446 /* Only tasks below the defNumberOfTasksWithSlot threshold can have slots */ 05447 if (uiTaskNumber>=defNumberOfTasksWithSlot) 05448 { /* For tasks that cannot have slots we send zero. */ 05449 uiSlotSize=0; } 05450 else 05451 { /* If the task has slots, we must deduce how many. */ 05452 #if (defSlotOneOnly == cfgTrue) 05453 /* With one slot we have, well one slot */ 05454 uiSlotSize = 1; 05455 #elif (defSlotDepthConstant == cfgTrue) 05456 /* if the number of slots is constant, we use that */ 05457 uiSlotSize = 2*defSlotDepthCollect; 05458 #else 05459 /* otherwise we use the value in flash */ 05460 uiSlotSize = 2*portFlashReadStruc(TtaskDefinitionBlock,pxTDBlist[uiTaskNumber],Tuint08,uiSlotDepth); 05461 #endif 05462 } 05463 /* Send the value */ 05464 pipe(uiSlotSize); 05465 /* Now send the actual slots. Now if uiSlotSize equals zero, we may not read the memory value of 05466 * taskTCB->uiTaskSlot since it does not exist, we can however calculate its address. */ 05467 Tuint08 * pTaskSlot = (Tuint08 *) &taskTCB->uiTaskSlot; 05468 /* Send the existing values, send null if it does not exist. */ 05469 if (uiSlotSize>0) { pipe(*pTaskSlot++); } else { pipe(0); } 05470 if (uiSlotSize>2) { pipe(*pTaskSlot++); } else { pipe(0); } 05471 if (uiSlotSize>4) { pipe(*pTaskSlot++); } else { pipe(0); } 05472 #else 05473 /* We must send zero's to compensate when no slots are used. */ 05474 genPipeInt16(0,pipe); 05475 genPipeInt16(0,pipe); 05476 #endif 05477 05478 /* If we collect watermarks send them trough. */ 05479 #if (cfgCheckWatermarks == cfgTrue) 05480 genPipeInt16(taskTCB->uiStackMax,pipe); 05481 pipe(taskTCB->uiRegisterUse); 05482 #else 05483 genPipeInt16(0,pipe); 05484 pipe(0); 05485 #endif 05486 } 05487 05488 #endif 05489 05490 05491 05492 #if ((cfgUseNestedCriticals == cfgTrue) && (includeTaskProtectGlobalCritical == cfgTrue)) || \ 05493 ((cfgIntGlobalOnly == cfgTrue) && (cfgIntTickTrack == cfgTrue) && (cfgUseNestedCriticals == cfgTrue) && (includeTaskProtectTickCritical == cfgTrue)) 05494 05495 05496 void taskEnterGlobalCritical(void) 05497 { /* If you want to make use level managed interrupt control, use this method. It keeps track 05498 * of the number of interrupts levels up to 4 or 16 levels per task. First we disable the 05499 * interrupt, if the are already disabled, this does not matter. */ 05500 privDisableGlobalInterrupts(); 05501 /* Tell what we are doing */ 05502 privTraceAPI(callIdTaskEnterGlobalCritical); 05503 /* Get the taskcontrolblock of the task that called this method. */ 05504 TtaskControlBlock * curTCB = privTcbList(privTaskNumber(defCurrentTaskNumber)); 05505 /* Check if the user uses this method properly. */ 05506 #if (cfgCheckMethodUse == cfgTrue) 05507 /* Check the capabilities of the current task */ 05508 privCheckCapabilities(callIdTaskEnterGlobalCritical, ((cfgCapCritical) & 0xFF) ); 05509 /* The number of levels is limited, check if we did not reach the maximum. */ 05510 if ((curTCB->defGlobField & defGlobGetMask) == defGlobMax) 05511 /* If so, report an error. */ 05512 { privShowError((errTaskNestingOverflowed | errTaskStateCurrent), callIdTaskEnterGlobalCritical, errCurrentTask ); } 05513 else 05514 /* if not we may safely increase the level number here */ 05515 { curTCB->defGlobField += defGlobInc; } 05516 #else 05517 /* At this place we assume that all is save and we increase the level just like that. */ 05518 curTCB->defGlobField += defGlobInc; 05519 #endif 05520 } 05521 05522 #endif 05523 05524 05525 #if (cfgUseNestedCriticals == cfgTrue) && (includeTaskProtectGlobalCritical == cfgTrue) || \ 05526 ((cfgIntGlobalOnly == cfgTrue) && (cfgIntTickTrack == cfgTrue) && (cfgUseNestedCriticals == cfgTrue) && (includeTaskProtectTickCritical == cfgTrue)) 05527 05528 void taskExitGlobalCritical(void) 05529 { /* If you want to make use level managed interrupt control, use this method. It keeps track 05530 * of the number of interrupts levels up to 4 or 16 levels per task. First tell what we are doing */ 05531 privTraceAPI(callIdTaskExitGlobalCritical); 05532 /* Get the taskcontrolblock of the task that called this method. */ 05533 TtaskControlBlock * curTCB = privTcbList(privTaskNumber(defCurrentTaskNumber)); 05534 /* Check if the user uses this method properly. */ 05535 #if (cfgCheckMethodUse == cfgTrue) 05536 /* Check the capabilities of the current task */ 05537 privCheckCapabilities(callIdTaskExitGlobalCritical, ((cfgCapCritical) & 0xFF) ); 05538 /* The number of levels is limited, check if we did not reach the minimum. */ 05539 if ((curTCB->defGlobField & defGlobGetMask) == defGlobMin) 05540 /* If so, report an error. */ 05541 { privShowError((errTaskNestingUnderflowed | errTaskStateCurrent), callIdTaskExitGlobalCritical, errCurrentTask ); } 05542 else 05543 /* if not we may safely decrease the level number here */ 05544 { curTCB->defGlobField -= defGlobInc; } 05545 #else 05546 /* At this place we assume that all is save and we decrease the level just like that. */ 05547 curTCB->defGlobField -= defGlobInc; 05548 #endif 05549 /* Now check if we reached the lowest level. If so, we must re-enable the interrupts. */ 05550 if ((curTCB->defGlobField & defGlobGetMask) == defGlobMin) 05551 { privEnableGlobalInterrupts(); } } 05552 05553 #endif 05554 05555 05556 #if (cfgUseNestedCriticals == cfgTrue) && (includeTaskProtectSwitchCritical == cfgTrue) 05557 05558 void taskEnterSwitchCritical(void) 05559 { /* If you want to make use level managed interrupt control, use this method. It keeps track 05560 * of the number of interrupts levels up to 4 or 16 levels per task. First we disable the 05561 * interrupt, if the are already disabled, this does not matter. Standard protection */ 05562 privEnterSysCritical(); 05563 /* Tell what we are doing */ 05564 privTraceAPI(callIdTaskEnterSwitchCritical); 05565 /* Get the taskcontrolblock of the task that called this method. */ 05566 TtaskControlBlock * curTCB = privTcbList(privTaskNumber(defCurrentTaskNumber)); 05567 /* Setting the dressing to 'runnable' prohibits the scheduling of an other task. */ 05568 curTCB->uiTaskStatus = (curTCB->uiTaskStatus & defBaseDressSetMask) | defBaseDressRunable; 05569 05570 /* Check if the user uses this method properly. */ 05571 #if (cfgCheckMethodUse == cfgTrue) 05572 /* Check the capabilities of the current task */ 05573 privCheckCapabilities(callIdTaskEnterSwitchCritical, ((cfgCapCritical) & 0xFF) ); 05574 /* The number of levels is limited, check if we did not reach the maximum. */ 05575 if ((curTCB->defSwitchField & defSwitchGetMask) == defSwitchMax) 05576 /* If so, report an error. */ 05577 { privShowError((errTaskNestingOverflowed | errTaskStateCurrent), callIdTaskEnterSwitchCritical, errCurrentTask ); } 05578 else 05579 /* if not we may safely increase the level number here */ 05580 { curTCB->defSwitchField += defSwitchInc; } 05581 #else 05582 /* At this place we assume that all is save and we increase the level just like that. */ 05583 curTCB->defSwitchField += defSwitchInc; 05584 #endif 05585 /* Done */ 05586 privExitSysCritical(); } 05587 05588 #endif 05589 05590 05591 #if (cfgUseNestedCriticals == cfgTrue) && (includeTaskProtectSwitchCritical == cfgTrue) 05592 05593 void taskExitSwitchCritical(void) 05594 { /* If you want to make use level managed interrupt control, use this method. It keeps track 05595 * of the number of interrupts levels up to 4 or 16 levels per task. Standard protection */ 05596 privEnterSysCritical(); 05597 /* Tell what we are doing */ 05598 privTraceAPI(callIdTaskExitSwitchCritical); 05599 /* Get the taskcontrolblock of the task that called this method. */ 05600 TtaskControlBlock * curTCB = privTcbList(privTaskNumber(defCurrentTaskNumber)); 05601 /* Check if the user uses this method properly. */ 05602 #if (cfgCheckMethodUse == cfgTrue) 05603 /* Check the capabilities of the current task */ 05604 privCheckCapabilities(callIdTaskExitSwitchCritical, ((cfgCapCritical) & 0xFF) ); 05605 /* The number of levels is limited, check if we did not reach the minimum. */ 05606 if ((curTCB->defSwitchField & defSwitchGetMask) == defSwitchMin) 05607 /* If so, report an error. */ 05608 { privShowError((errTaskNestingUnderflowed | errTaskStateCurrent), callIdTaskExitSwitchCritical, errCurrentTask ); } 05609 else 05610 /* if not we may safely decrease the level number here */ 05611 { curTCB->defSwitchField -= defSwitchInc; } 05612 #else 05613 /* At this place we assume that all is save and we decrease the level just like that. */ 05614 curTCB->defSwitchField -= defSwitchInc; 05615 #endif 05616 /* Now check if we reached the lowest level. If so, we must re-enable the switches. */ 05617 if ((curTCB->defSwitchField & defSwitchGetMask) == defSwitchMin) 05618 { /* Setting the dressing to 'done' enables the scheduling of an other task. */ 05619 curTCB->uiTaskStatus = (curTCB->uiTaskStatus & defBaseDressSetMask) | defBaseDressDone; } 05620 privExitSysCritical(); } 05621 05622 #endif 05623 05624 05625 #if (cfgIntGlobalOnly == cfgFalse) && (cfgIntTickTrack == cfgTrue) && (cfgUseNestedCriticals == cfgTrue) && (includeTaskProtectTickCritical == cfgTrue) 05626 05627 void taskEnterTickCritical(void) 05628 { /* If you want to make use level managed interrupt control, use this method. It keeps track 05629 * of the number of interrupts levels up to a maximum per task. First we disable the 05630 * interrupt, if the are already disabled, this does not matter. Note we do not need 05631 * further protection, since when we have disabled Tick interrupts, we can only anticipate 05632 * interrupts which may not invoke a context switch. They do no harm.*/ 05633 privDisableTickInterrupts(); 05634 /* Tell what we are doing */ 05635 privTraceAPI(callIdTaskEnterTickCritical); 05636 /* Get the taskcontrolblock of the task that called this method. */ 05637 TtaskControlBlock * curTCB = privTcbList(privTaskNumber(defCurrentTaskNumber)); 05638 /* Check if the user uses this method properly. */ 05639 #if (cfgCheckMethodUse == cfgTrue) 05640 /* Check the capabilities of the current task */ 05641 privCheckCapabilities(callIdTaskEnterTickCritical, ((cfgCapCritical) & 0xFF) ); 05642 /* The number of levels is limited, check if we did not reach the maximum. */ 05643 if ((curTCB->defTickField & defTickGetMask) == defTickMax) 05644 /* If so, report an error. */ 05645 { privShowError((errTaskNestingOverflowed | errTaskStateCurrent), callIdTaskEnterTickCritical, errCurrentTask ); } 05646 else 05647 /* if not we may safely increase the level number here */ 05648 { curTCB->defTickField += defTickInc; } 05649 #else 05650 /* At this place we assume that all is save and we increase the level just like that. */ 05651 curTCB->defTickField += defTickInc; 05652 #endif 05653 } 05654 05655 #endif 05656 05657 05658 #if (cfgIntGlobalOnly == cfgFalse) && (cfgIntTickTrack == cfgTrue) && (cfgUseNestedCriticals == cfgTrue) && (includeTaskProtectTickCritical == cfgTrue) 05659 05660 void taskExitTickCritical(void) 05661 {/* If you want to make use level managed interrupt control, use this method. It keeps track 05662 * of the number of interrupts levels up to a maximum per task. First we disable the 05663 * interrupt, if the are already disabled, this does not matter. Note we do not need 05664 * further protection, since when we have disabled Tick interrupts before we enter, and 05665 * we and can only anticipate interrupts which may not invoke a context switch. They do no harm. */ 05666 privTraceAPI(callIdTaskExitTickCritical); 05667 /* Get the taskcontrolblock of the task that called this method. */ 05668 { TtaskControlBlock * curTCB = privTcbList(privTaskNumber(defCurrentTaskNumber)); 05669 /* Check if the user uses this method properly. */ 05670 #if (cfgCheckMethodUse == cfgTrue) 05671 /* Check the capabilities of the current task */ 05672 privCheckCapabilities(callIdTaskExitTickCritical, ((cfgCapCritical) & 0xFF) ); 05673 /* The number of levels is limited, check if we did not reach the minimum. */ 05674 if ((curTCB->defTickField & defTickGetMask) == defTickMin) 05675 /* If so, report an error. */ 05676 { privShowError((errTaskNestingUnderflowed | errTaskStateCurrent), callIdTaskExitTickCritical, errCurrentTask ); } 05677 else 05678 /* if not we may safely decrease the level number here */ 05679 { curTCB->defTickField -= defTickInc; } 05680 #else 05681 /* At this place we assume that all is save and we decrease the level just like that. */ 05682 curTCB->defTickField -= defTickInc; 05683 #endif 05684 /* Now check if we reached the lowest level. If so, we must re-enable the interrupts. */ 05685 if ((curTCB->defTickField & defTickGetMask) == defTickMin) 05686 { privEnableTickInterrupts(); } } } 05687 05688 #endif 05689 05690 05691 #if (cfgCheckTrace == cfgTrue) && (includeGenTrace == cfgTrue) 05692 05693 void genTraceByteInfo(Tbyte bUser) 05694 { /* Use this function if you as user want to send a byte trough the trace utility. Do not 05695 * use portTrace directly, since most codes are already occupied. First we enter the 05696 * critical section because we do not want that an other task gets in between and sends 05697 * an other byte. 05698 * The user byte consists of two bytes of information. */ 05699 privEnterSysCritical(); 05700 /* Tell that a user byte is coming. */ 05701 privTrace(traceUserByteMessage); 05702 /* Send the user byte */ 05703 privTrace(bUser); 05704 /* done */ 05705 privExitSysCritical(); } 05706 05707 #endif 05708 05709 05710 #if (cfgCheckTrace == cfgTrue) && (includeGenTrace == cfgTrue) 05711 05712 void genTraceWordInfo(Tword wUser) 05713 { /* Use this function if you as user want to send a word trough the trace utility. Do not 05714 * use portTrace directly, since most codes are already occupied. First we enter the 05715 * critical section because we do not want that an other task gets in between and sends 05716 * an other byte. 05717 * The user byte consists of two bytes of information. */ 05718 privEnterSysCritical(); 05719 /* Tell that a user byte is coming. */ 05720 privTrace(traceUserWordMessage); 05721 /* Send the user word, big endian! */ 05722 privTrace((Tbyte)(wUser>>8)); 05723 privTrace((Tbyte)(wUser)); 05724 /* done */ 05725 privExitSysCritical(); } 05726 05727 #endif 05728 05729 05730 #if (cfgCheckTrace == cfgTrue) && (includeGenTrace == cfgTrue) 05731 05732 void genTraceMarker(void) 05733 { /* Use this function to send a marker. Markers can be used to quickly find some 05734 * part of the trace information. 05735 * at all.*/ 05736 privEnterSysCritical(); 05737 /* Send the marker */ 05738 privTrace(traceMarker); 05739 /* done */ 05740 privExitSysCritical(); } 05741 05742 #endif 05743 05744 05745 #if (cfgUseSynchronization != cfgSyncNon) && (includeTaskWaitForTasks == cfgTrue) 05746 05747 /* Depending on the fact if we want to make use of the timeout on locking, we introduce 05748 * the extra parameter uiTicksToWait. */ 05749 #if (cfgUseTimeout == cfgTrue) 05750 void privWaitForTasksBody(Tuint08 uiSlot, Tuint08 uiNumberOfTasks, Tuint16 uiTicksToWait) 05751 #else 05752 void privWaitForTasksBody(Tuint08 uiSlot, Tuint08 uiNumberOfTasks) 05753 #endif 05754 { /* Use this method to synchronize more than two tasks. This is a switching call, 05755 * let us first initialize the OS. (It is a 'body' function too, see the explanation 05756 * of this design elsewhere.) */ 05757 privInitOsSwitch(); 05758 /* Tell what we are doing */ 05759 privTraceAPI(callIdTaskWaitForTasks); 05760 /* Get the current task number */ 05761 Tuint08 uiCurrentTask = privTaskNumber(defCurrentTaskNumber); 05762 /* Check if the user uses this method properly. */ 05763 #if (cfgCheckMethodUse == cfgTrue) 05764 /* Check the capabilities of the current task */ 05765 privCheckCapabilities(callIdTaskWaitForTasks, ((cfgCapSynchronization) & 0xFF) ); 05766 /* Check if the current task has the right to make use of a slot. (Check remeains needed even if we check 05767 * capabilities, since we may have capabilities but no slotstack defined.) */ 05768 if (uiCurrentTask >= defNumberOfTasksWithSlot) 05769 /* If not report the error. */ 05770 { privShowError((errTaskHoldsNoSlots | errTaskStateCurrent | errOsStateAsIs), callIdTaskWaitForTasks, errCurrentTask ); } 05771 /* The zero slot is reserved to indicate there is no lock, thus it cannot be actively used. */ 05772 if (uiSlot == defSlotFree) 05773 /* Report an error and stop the task. */ 05774 { privShowError((errSlotZeroUsed | errTaskStateCurrent | errOsStateAsIs), callIdTaskWaitForTasks, errCurrentTask ); } 05775 /* Double slots are not allowed */ 05776 if ((uiSlot & defSlotLeftGetMask) != defSlotLeftFree) 05777 /* Report an error and stop the task. */ 05778 { privShowError((errSlotDoubleUsed | errTaskStateCurrent | errOsStateAsIs), callIdTaskWaitForTasks, errCurrentTask ); } 05779 /* Check the type of the slot which is coupled to its number. */ 05780 if ((uiSlot < defNumberWaitBegin) || (uiSlot >= defNumberWaitEnd)) 05781 /* If so report an error. */ 05782 { privShowError((errSlotTypeMismatch | errTaskStateCurrent | errOsStateAsIs), callIdTaskWaitForTasks, errCurrentTask ); } 05783 /* The timeout is implemented as a delay, thus may not exceed the maximum delay time.*/ 05784 #if (cfgUseTimeout == cfgTrue) 05785 /* Check the capabilities of the current task */ 05786 privCheckCapabilities(callIdTaskWaitForTasks, ((cfgCapTimeout) & 0xFF) ); 05787 /* Check if we do not violate the max delay time */ 05788 if (uiTicksToWait > defDelayTimeMax) 05789 /* Report an error and stop the task. */ 05790 { privShowError((errTaskDelayTooLong | errTaskStateCurrent | errOsStateAsIs), callIdTaskWaitForTasks, errCurrentTask ); } 05791 #endif 05792 #endif 05793 /* First look if the requested number of tasks is already reached. Note that the system does not remember this 05794 * number, you have to supply it on every call, and that should be constant. */ 05795 TtaskControlBlock * curTCB = privTcbList(uiCurrentTask); 05796 /* There is one more check we must perform */ 05797 #if (cfgCheckMethodUse == cfgTrue) && ((includeTaskProtectSwitchTasks == cfgTrue) || (includeTaskProtectSwitchCritical == cfgTrue)) 05798 /* And that is to see if we do not have a dominant task at hand */ 05799 if ((curTCB->uiTaskStatus & defBaseDressGetMask) == defBaseDressRunable) 05800 /* Report an error and stop the task. */ 05801 { privShowError((errIllegalDominantState | errTaskStateCurrent | errOsStateAsIs), callIdTaskWaitForTasks, errCurrentTask ); } 05802 #endif 05803 Tuint08 uiLoopTask; 05804 /* Set the counter that will count the number of blocked task to one, representing the current task */ 05805 Tuint08 uiBlockCount = 1; 05806 /* Now loop through all tasks. */ 05807 for (uiLoopTask=0; uiLoopTask<defNumberOfTasksWithSlot; uiLoopTask++) 05808 { TtaskExtendedControlBlock * loopTCB = (TtaskExtendedControlBlock *) privTcbList(uiLoopTask); 05809 /* If the task contains the slot, it must be blocking (we do not need to check that), and 05810 * since this slot can never be used in a double block, we do not need to check that. But 05811 * if we have cfgSyncSingleBlock the left may be filled with some slot on which this task 05812 * has a free lock. That must be eliminated, the other cases cfgSyncSingleSlot and cfgSyncDoubleBlock 05813 * pose no problems. */ 05814 #if (cfgUseSynchronization == cfgSyncSingleBlock) 05815 if ((loopTCB->uiTaskSlot & defSlotRightGetMask) == uiSlot) { uiBlockCount++; } 05816 #else 05817 if (loopTCB->uiTaskSlot == uiSlot) { uiBlockCount++; } 05818 #endif 05819 } 05820 /* Now test if enough tasks are blocking */ 05821 if (uiBlockCount >= uiNumberOfTasks) 05822 { /* We are about to release, which is equivalent to an acquired lock, report so */ 05823 privTrace(traceLockAcquire); 05824 /* Yes, there are so release the other tasks */ 05825 privReleaseWait(uiSlot); 05826 /* Also, we have succeeded, so we return true, if this facility has been compiled in. */ 05827 #if (defUseBoolReturns == cfgTrue) 05828 curTCB->defRetField = (curTCB->defRetField & defRetSetMask ) | defRetTrue; 05829 #endif 05830 /* We are done, so enter the OS to start a new task. */ 05831 privEnterOS(defActionTaskStateKeep); } 05832 else 05833 { /* If the lock was not occupied, or there were not enough tasks, we must add ourselves to the 05834 * waiting list. Say so to the outside world. */ 05835 privTrace(traceLockReject); 05836 /* Make room for a new lock.*/ 05837 privOperateSlotStack((uiCurrentTask| defSlotOperateIncreaseAction), uiSlot); 05838 /* First handle the timeout so the compiler may dump this variable. */ 05839 #if (cfgUseTimeout == cfgTrue) 05840 /* If we make use of timeouts, set the delay variable, which is used for the timeout. */ 05841 if (uiTicksToWait != defLockBlockInfinite) { privDelayCalcFromNow(uiTicksToWait); } 05842 #endif 05843 /* Lock the task */ 05844 curTCB->uiTaskStatus = (curTCB->uiTaskStatus & (defBaseModeSetMask & defBaseBlockStateSetMask & defBaseDressSetMask)) | (defBaseModeSync | defBaseBlockStateBlocked | defBaseDressSlot); 05845 /* At this point it make no sense to perform priority lifting. This is because this is 05846 * task cannot hold an other task hostage with a low priority. */ 05847 privEnterOS(defActionTaskStateSwitch); } } 05848 05849 #endif 05850 05851 05852 #if (cfgUseSynchronization != cfgSyncNon) && (includeGenWaitRelease == cfgTrue) 05853 05854 void genWaitRelease(Tuint08 uiSlot) 05855 { /* Use this method to release all blocks on a particular locks, but only those placed 05856 * by WaitForTasks of WaitForOtherTasks. The call is non switching (needed so we can call it from 05857 * an isr), so we must protect ourselves.*/ 05858 privEnterSysCritical(); 05859 /* Tell what we are doing */ 05860 privTraceAPI(callIdGenWaitRelease); 05861 /* Check if the user uses this method properly. */ 05862 #if (cfgCheckMethodUse == cfgTrue) 05863 /* If we have no protection for the OS from interrupts ... */ 05864 #if (cfgIntOsProtected == cfgFalse) 05865 /* we may not arrive here from an isr */ 05866 if ((uiOsStatus & defContextGetMask) == defContextStateIsr) 05867 /* and if we do this is a fatal error. */ 05868 { privShowError((fatIllegalCallfromISR | errTaskStateNon), callIdGenWaitRelease, errNoInfo ); } 05869 #endif 05870 /* The zero slot is reserved to indicate there is no lock, thus it cannot be actively used. */ 05871 if (uiSlot == defSlotFree) 05872 /* Report an error and stop the task. */ 05873 { privShowError((errSlotZeroUsed | errTaskStateCurrent), callIdGenWaitRelease, errCurrentTask ); } 05874 /* Check the type of the slot which is coupled to its number. */ 05875 if ((uiSlot < defNumberWaitBegin) || (uiSlot >= defNumberWaitEnd)) 05876 /* If so report an error. */ 05877 { privShowError((errSlotTypeMismatch | errTaskStateCurrent), callIdGenWaitRelease, errCurrentTask ); } 05878 #endif 05879 /* Release everything */ 05880 privReleaseWait(uiSlot); 05881 /* Done, exit the critical zone. */ 05882 privExitSysCritical(); } 05883 05884 #endif 05885 05886 05887 #if (cfgUseSynchronization != cfgSyncNon) && ( (includeTaskQueu == cfgTrue) || (includeTaskMutex == cfgTrue) ) 05888 05889 /* Depending on the fact if we want to make use of the timeout on locking, we introduce 05890 * the extra parameter uiTicksToWait. */ 05891 #if (cfgUseTimeout == cfgTrue) 05892 #if (cfgUseSynchronization == cfgSyncDoubleBlock) 05893 void privSyncRequestBody(Tuint08 uiSlotSlot, Tsint08 siFreeLeftFilling, Tsint08 siFreeRightFilling, Tuint16 uiTicksToWait) 05894 #else 05895 void privSyncRequestBody(Tuint08 uiSlotSlot, Tsint08 siFreeRightFilling, Tuint16 uiTicksToWait) 05896 #endif 05897 #else 05898 #if (cfgUseSynchronization == cfgSyncDoubleBlock) 05899 void privSyncRequestBody(Tuint08 uiSlotSlot, Tsint08 siFreeLeftFilling, Tsint08 siFreeRightFilling) 05900 #else 05901 void privSyncRequestBody(Tuint08 uiSlotSlot, Tsint08 siFreeRightFilling) 05902 #endif 05903 #endif 05904 { /* Use this method to test how many bytes can be read from/ written to a queue and lock the queue 05905 * for that purpose, siFreeFilling>0: readable, siFreeFilling<0: writable bytes, 05906 * siFreeFilling = 0 no check on size. This is a switching call, let us first initialize 05907 * the OS. (It is a 'body' function too, see the explanation of this design elsewhere.) */ 05908 privInitOsSwitch(); 05909 /* Tell what we are doing */ 05910 privTraceAPI(callIdTaskSyncRequest); 05911 /* Extract the left and right slots. */ 05912 Tuint08 uiRightSlot = (uiSlotSlot & defSlotRightGetMask) >> defSlotRightShift; 05913 /*We only need the left slot in special situations. */ 05914 #if (cfgUseSynchronization == cfgSyncDoubleBlock) 05915 Tuint08 uiLeftSlot = (uiSlotSlot & defSlotLeftGetMask) >> defSlotLeftShift; 05916 #endif 05917 /* Get the current task number */ 05918 Tuint08 uiCurrentTask = privTaskNumber(defCurrentTaskNumber); 05919 /* Check if the user uses this method properly. */ 05920 #if (cfgCheckMethodUse == cfgTrue) 05921 /* Check the capabilities of the current task */ 05922 privCheckCapabilities(callIdTaskSyncRequest, ((cfgCapSynchronization) & 0xFF) ); 05923 /* Check if the current task has the right to make use of a slot. (Check remeains needed even if we check 05924 * capabilities, since we may have capabilities but no slotstack defined.) */ 05925 if (uiCurrentTask >= defNumberOfTasksWithSlot) 05926 /* If not report the error. */ 05927 { privShowError((errTaskHoldsNoSlots | errTaskStateCurrent | errOsStateAsIs), callIdTaskSyncRequest, errCurrentTask ); } 05928 /* Check if the preprocessor already saw that the slot is of the wrong type. Note that we 'misused' 05929 * the value 0xF0 to pass this information. Formally that number could also have been passed directly 05930 * but that is an error two btw, but of a different kind. Here we assume it is not. The OnName macros 05931 * can never pass a slot number zero, so it may only collide with a manual call on taskSyncRequest with 05932 * 0xF0 as slot parameter. */ 05933 if (uiSlotSlot == defCheckSlotTypeError) 05934 { privShowError((errSlotTypeMismatch | errTaskStateCurrent | errOsStateAsIs), callIdTaskSyncRequest, errCurrentTask ); } 05935 /* The zero slot is reserved to indicate there is no lock, thus it cannot be actively used. */ 05936 if (uiRightSlot == defSlotRightFree) 05937 /* Report an error and stop the task. */ 05938 { privShowError((errSlotZeroUsed | errTaskStateCurrent | errOsStateAsIs), callIdTaskSyncRequest, errCurrentTask ); } 05939 /* Check the type of the slot which is coupled to its number, and if mutexes do not have Fillings */ 05940 if ( ( (uiRightSlot != defSlotRightFree) && ((uiRightSlot < defNumberQueuBegin) || (uiRightSlot >= defNumberMutexEnd ))) || 05941 ( (siFreeRightFilling != 0) && ((uiRightSlot >= defNumberMutexBegin) || (uiRightSlot < defNumberMutexEnd ))) ) 05942 /* If so report an error. */ 05943 { privShowError((errSlotTypeMismatch | errTaskStateCurrent | errOsStateAsIs), callIdTaskSyncRequest, errCurrentTask ); } 05944 #if (cfgUseSynchronization == cfgSyncDoubleBlock) 05945 if ( ( (uiLeftSlot != defSlotLeftFree) && ((uiLeftSlot < defNumberQueuBegin) || (uiLeftSlot >= defNumberMutexEnd ))) || 05946 ( (siFreeLeftFilling != 0) && ((uiLeftSlot >= defNumberMutexBegin) || (uiLeftSlot < defNumberMutexEnd ))) ) 05947 /* If so report an error. */ 05948 { privShowError((errSlotTypeMismatch | errTaskStateCurrent | errOsStateAsIs), callIdTaskSyncRequest, errCurrentTask ); } 05949 /* Check if not two identical slots are locked */ 05950 if (uiRightSlot == uiLeftSlot) 05951 /* If so report an error. */ 05952 { privShowError((errSlotTwins | errTaskStateCurrent | errOsStateAsIs), callIdTaskSyncRequest, errCurrentTask ); } 05953 #else 05954 /* Double slots are not allowed */ 05955 if ((uiSlotSlot & defSlotLeftGetMask) != defSlotLeftFree) 05956 /* Report an error and stop the task. */ 05957 { privShowError((errSlotDoubleUsed | errTaskStateCurrent | errOsStateAsIs), callIdTaskSyncRequest, errCurrentTask ); } 05958 #endif 05959 #if (defUseQueus == cfgTrue) 05960 /* It is an error to read more bytes from, or write to the queue than the queue contains, it would 05961 * block indefinitely or always return false. */ 05962 Tuint08 uiRightSize = privGetQueuSize(uiRightSlot-1); 05963 /* we want read bytes, see if we do not read to many */ 05964 if ((siFreeRightFilling>0) && (((Tuint08) siFreeRightFilling)>uiRightSize) ) 05965 { privShowError((errQueuReadLimit | errTaskStateCurrent | errOsStateAsIs), callIdTaskSyncRequest, errCurrentTask ); } 05966 /* we want write bytes, see if we do not write to many */ 05967 if ((siFreeRightFilling<0) && (((Tuint08) -siFreeRightFilling)>uiRightSize) ) 05968 { privShowError((errQueuWriteLimit | errTaskStateCurrent | errOsStateAsIs), callIdTaskSyncRequest, errCurrentTask ); } 05969 /* The timeout is implemented as a delay, thus may not exceed the maximum delay time.*/ 05970 #if (cfgUseSynchronization == cfgSyncDoubleBlock) 05971 Tuint08 uiLeftSize = privGetQueuSize(uiLeftSlot-1); 05972 if ((siFreeLeftFilling>0) && (((Tuint08) siFreeLeftFilling)>uiLeftSize) ) 05973 { privShowError((errQueuReadLimit | errTaskStateCurrent | errOsStateAsIs), callIdTaskSyncRequest, errCurrentTask ); } 05974 /* we want write bytes, see if we do not write to many */ 05975 if ((siFreeLeftFilling<0) && (((Tuint08) -siFreeLeftFilling)>uiLeftSize) ) 05976 { privShowError((errQueuWriteLimit | errTaskStateCurrent | errOsStateAsIs), callIdTaskSyncRequest, errCurrentTask ); } 05977 #endif 05978 #endif 05979 #if (cfgUseTimeout == cfgTrue) 05980 /* Check the capabilities of the current task */ 05981 privCheckCapabilities(callIdTaskSyncRequest, ((cfgCapTimeout) & 0xFF) ); 05982 /* Check if we do not violate the max delay time */ 05983 if (uiTicksToWait > defDelayTimeMax) 05984 /* Report an error and stop the task. */ 05985 { privShowError((errTaskDelayTooLong | errTaskStateCurrent | errOsStateAsIs), callIdTaskSyncRequest, errCurrentTask ); } 05986 #endif 05987 #endif 05988 /* Arriving at this point, we assume we are going to try to lock a queue. If we get access to a queue 05989 * depends on two questions. If the queue is not already locked, and if the number of bytes (to read 05990 * or write) fit. Get a pointer to the task control block for operations. */ 05991 TtaskExtendedControlBlock * curTCB = (TtaskExtendedControlBlock *) privTcbList(uiCurrentTask); 05992 /* There is one more check we must perform */ 05993 #if (cfgCheckMethodUse == cfgTrue) && ((includeTaskProtectSwitchTasks == cfgTrue) || (includeTaskProtectSwitchCritical == cfgTrue)) 05994 /* And that is to see if we do not have a dominant task at hand */ 05995 if ((curTCB->uiTaskStatus & defBaseDressGetMask) == defBaseDressRunable) 05996 /* Report an error and stop the task. */ 05997 { privShowError((errIllegalDominantState | errTaskStateCurrent | errOsStateAsIs), callIdTaskSyncRequest, errCurrentTask ); } 05998 #endif 05999 /* When we arive here there are we may already own the slot, or own other slots. Thats fine. The only thing we 06000 * must be sure is that no other task owns it which is not blocking. That other task may not posses the slot 06001 * and block on some other slot to, since that implies free possesion of the queue slot when the other 06002 * block is released. This is all tested in privFreeLockAbsent*/ 06003 Tbool bFreeLockAbsent; 06004 #if (cfgUseSynchronization == cfgSyncDoubleBlock) 06005 bFreeLockAbsent = privFreeLockAbsent(uiLeftSlot) && privFreeLockAbsent(uiRightSlot); 06006 #else 06007 bFreeLockAbsent = privFreeLockAbsent(uiRightSlot); 06008 #endif 06009 /* Now let us register the use of the slots, which is needed anyway, whether we must block or can 06010 * continue. This must be done after the check for freeLock.*/ 06011 privOperateSlotStack((uiCurrentTask| defSlotOperateIncreaseAction), uiSlotSlot); 06012 /* If we have a mutex, no further testing is needed (privSizeFitsQueu returns true for mutexes) and 06013 * if there are no queues present we can leave the test out all together. */ 06014 #if (defUseQueus == cfgTrue) 06015 #if (cfgUseSynchronization == cfgSyncDoubleBlock) 06016 if ( bFreeLockAbsent && privSizeFitsQueu(uiLeftSlot,siFreeLeftFilling) && privSizeFitsQueu(uiRightSlot,siFreeRightFilling) ) 06017 #else 06018 if ( bFreeLockAbsent && privSizeFitsQueu(uiRightSlot,siFreeRightFilling) ) 06019 #endif 06020 #else 06021 if (bFreeLockAbsent) 06022 #endif 06023 { /* OK, we have finally found out that we may take possession of the queue, let the outside world know. */ 06024 privTrace(traceLockAcquire); 06025 /* the slots where already registered, so there is not a lot left to do, since 06026 * obtaining the lock on the slot was a success. */ 06027 #if (defUseBoolReturns == cfgTrue) 06028 /* return true */ 06029 curTCB->defRetField = ( curTCB->defRetField & defRetSetMask ) | defRetTrue; 06030 #endif 06031 /* Done, ask the OS if we may continue our business. */ 06032 privEnterOS(defActionTaskStateKeep); } 06033 else 06034 { /* OK, unfortunately we must wait until some other task has run and changed the conditions 06035 * so that we can run. report so to the ouside world. */ 06036 privTrace(traceLockReject); 06037 /* First handle the timeout so the compiler may dump this variable. */ 06038 #if (cfgUseTimeout == cfgTrue) 06039 /* If we make use of timeouts, set the delay variable, which is used for the timeout. */ 06040 if (uiTicksToWait != defLockBlockInfinite) { privDelayCalcFromNow(uiTicksToWait); } 06041 #endif 06042 /* thus block the task */ 06043 curTCB->uiTaskStatus = (curTCB->uiTaskStatus & (defBaseModeSetMask & defBaseBlockStateSetMask & defBaseDressSetMask)) | (defBaseModeSync | defBaseBlockStateBlocked | defBaseDressSlot); 06044 /* Of course, we must store somewhere what the release condition for this particular block is. 06045 * This is the siFreeFilling parameter, which says it all. Store it in the siQueuLock field. */ 06046 #if (defUseQueus == cfgTrue) 06047 curTCB->siQueuRightLock = siFreeRightFilling; 06048 #if (cfgUseSynchronization == cfgSyncDoubleBlock) 06049 curTCB->siQueuLeftLock = siFreeLeftFilling; 06050 #endif 06051 #endif 06052 /* At this point we must priority lift. The current task could be a very important task, but 06053 * is now blocked, maybe waiting for some low prio task for release. To make sure we do not 06054 * deadlock let us raise the priorities of all tasks on this lock to the highest available 06055 * level. */ 06056 #if (cfgUsePriorityLifting == cfgTrue) 06057 privLiftLocksOnSlot(uiRightSlot); 06058 #if (cfgUseSynchronization == cfgSyncDoubleBlock) 06059 privLiftLocksOnSlot(uiLeftSlot); 06060 #endif 06061 #endif 06062 /* We are done, and, since we cannot continue, ask the OS to switch to an other task. */ 06063 privEnterOS(defActionTaskStateSwitch); } } 06064 06065 #endif 06066 06067 06068 #if (cfgUseSynchronization != cfgSyncNon) && ( (includeTaskQueu == cfgTrue) || (includeTaskMutex == cfgTrue) ) 06069 06070 void privSyncReleaseBody(Tuint08 uiSlotSlot) 06071 { /* Call this if you want to release a queue, It is a 'body' function too, see 06072 * the explanation of this design elsewhere. */ 06073 privInitOsSwitch(); 06074 /* Tell what we are doing */ 06075 privTraceAPI(callIdTaskSyncRelease); 06076 /* Check if the user uses this method properly. */ 06077 Tuint08 uiRightSlot = (uiSlotSlot & defSlotRightGetMask) >> defSlotRightShift; 06078 #if (cfgUseSynchronization == cfgSyncDoubleBlock) 06079 Tuint08 uiLeftSlot = (uiSlotSlot & defSlotLeftGetMask) >> defSlotLeftShift; 06080 #endif 06081 /* Get the current task number */ 06082 Tuint08 uiCurrentTask = privTaskNumber(defCurrentTaskNumber); 06083 /* Check if the user uses this method properly. */ 06084 #if (cfgCheckMethodUse == cfgTrue) 06085 /* Check the capabilities of the current task */ 06086 privCheckCapabilities(callIdTaskSyncRelease, ((cfgCapSynchronization) & 0xFF) ); 06087 /* Check if the current task has the right to make use of a slot. (Check remeains needed even if we check 06088 * capabilities, since we may have capabilities but no slotstack defined.) */ 06089 if (uiCurrentTask >= defNumberOfTasksWithSlot) 06090 /* If not report the error. */ 06091 { privShowError((errTaskHoldsNoSlots | errTaskStateCurrent | errOsStateAsIs), callIdTaskSyncRelease, errCurrentTask ); } 06092 /* Check if the preprocessor allready saw that the slot is of the wrong type. Note that we 'misused' 06093 * the value 0xF0 to pass this information. Formally that number could also have been passed directly 06094 * but that is an error two btw, but of a different kind. Here we assume it is not. The OnName macros 06095 * can never pass a slotnumber zero, so it may only collide with a manual call on taskSyncRequest with 06096 * 0xF0 as slot parameter. */ 06097 if (uiSlotSlot == defCheckSlotTypeError) 06098 { privShowError((errSlotTypeMismatch | errTaskStateCurrent | errOsStateAsIs), callIdTaskSyncRelease, errCurrentTask ); } 06099 /* The zero slot is reserved to indicate there is no lock, thus it cannot be actively used. */ 06100 if (uiRightSlot == defSlotRightFree) 06101 /* Report an error and stop the task. */ 06102 { privShowError((errSlotZeroUsed | errTaskStateCurrent | errOsStateAsIs), callIdTaskSyncRelease, errCurrentTask ); } 06103 /* Check the type of the slot which is coupled to its number. */ 06104 if ( ( (uiRightSlot != defSlotRightFree) && ((uiRightSlot < defNumberQueuBegin) || (uiRightSlot >= defNumberMutexEnd ))) ) 06105 /* If so report an error. */ 06106 { privShowError((errSlotTypeMismatch | errTaskStateCurrent | errOsStateAsIs), callIdTaskSyncRelease, errCurrentTask ); } 06107 #if (cfgUseSynchronization == cfgSyncDoubleBlock) 06108 if ( ( (uiLeftSlot != defSlotLeftFree) && ((uiLeftSlot < defNumberQueuBegin) || (uiLeftSlot >= defNumberMutexEnd ))) ) 06109 /* If so report an error. */ 06110 { privShowError((errSlotTypeMismatch | errTaskStateCurrent | errOsStateAsIs), callIdTaskSyncRelease, errCurrentTask ); } 06111 /* Check if not two identical slots are locked */ 06112 if (uiRightSlot == uiLeftSlot) 06113 /* If so report an error. */ 06114 { privShowError((errSlotTwins | errTaskStateCurrent | errOsStateAsIs), callIdTaskSyncRelease, errCurrentTask ); } 06115 #else 06116 /* Double slots are not allowed */ 06117 if ((uiSlotSlot & defSlotLeftGetMask) != defSlotLeftFree) 06118 /* Report an error and stop the task. */ 06119 { privShowError((errSlotDoubleUsed | errTaskStateCurrent | errOsStateAsIs), callIdTaskSyncRelease, errCurrentTask ); } 06120 #endif 06121 #endif 06122 /* We must remove one lock on the requested slot. We assume we posses that slot, if not 06123 * we cannot remove one. Now, the function returns with true if, after removal, more 06124 * slots of the present slot number are present, in that case we may not release a new 06125 * task. If false the slot was the last one and it is save to release a new task. */ 06126 #if (cfgUseSynchronization == cfgSyncDoubleBlock) 06127 /* See if the right slot is no longer used by this task, after on removal */ 06128 Tbool bRightSlotAbsent = !privOperateSlotStack((uiCurrentTask | defSlotOperateDecreaseAction), uiRightSlot); 06129 /* See if the left slot is no longer used by this task, after on removal */ 06130 Tbool bLeftSlotAbsent = !privOperateSlotStack((uiCurrentTask | defSlotOperateDecreaseAction), uiLeftSlot); 06131 /* If we changed something at the slotstack it may be needed to check if some tasks must be released. 06132 * Since it is not possible that due to this change is new task must be release if the task 06133 * still holds an other copy of the slot blocked or free, we need not to Release anything. If we 06134 * do, it does not matter, but it is extra overhead. */ 06135 if (bRightSlotAbsent | bLeftSlotAbsent) { privReleaseSyncBlockingTasks(); } 06136 /* If we made use of priority lifting ... */ 06137 #if (cfgUsePriorityLifting == cfgTrue) 06138 /* this task must regain its original priority, if no slots are occupied any more. 06139 * If the slot is still present, the slotstack cannot be empty so a call is not 06140 * needed. It does not harm eighter, but takes a lot of cycles to complete. */ 06141 if (bRightSlotAbsent & bLeftSlotAbsent) { privRestoreInitialPriority(uiCurrentTask); } 06142 #endif 06143 #else 06144 /* See if the right slot is no longer used by this task, after on removal */ 06145 Tbool bRightSlotAbsent = !privOperateSlotStack((uiCurrentTask | defSlotOperateDecreaseAction), uiRightSlot); 06146 /* If we changed something at the slotstack it may be needed to check if some tasks must be released. 06147 * Since it is not possible that due to this change is new task must be release if the task 06148 * still holds an other copy of the slot blocked or free, we need not to Release anything. If we 06149 * do, it does not matter, but it is extra overhead. */ 06150 if (bRightSlotAbsent) { privReleaseSyncBlockingTasks(); } 06151 /* If we made use of priority lifting ... */ 06152 #if (cfgUsePriorityLifting == cfgTrue) 06153 /* this task must regain its original priority, if no slots are occupied any more. 06154 * If the slot is still present, the slotstack cannot be empty so a call is not 06155 * needed. It does not harm eighter, but takes a lot of cycles to complete. */ 06156 if (bRightSlotAbsent) { privRestoreInitialPriority(uiCurrentTask); } 06157 #endif 06158 #endif 06159 /* We are done, but the task may not yet be over, ask the OS to reschedule me. */ 06160 privEnterOS(defActionTaskStateKeep); } 06161 06162 #endif 06163 06164 06165 06166 #if (cfgUseSynchronization != cfgSyncNon) && (defUseQueus == cfgTrue) && (includeGenQueuWrite == cfgTrue) 06167 06168 void genQueuWrite(Tuint08 uiSlot, Tbyte bItem) 06169 { /* Use this method to put a byte on a queue. Usually you lock that queuee first by taskQueuRequest, so 06170 * you are sure you have full control over the queue and the byte you write will indeed fit on 06171 * the queue. However, you do not always have this possibility, for example if you are in an isr. 06172 * In that case you can obtain the number of free bytes with genQueuWriteable or you can just 06173 * flood the queue. Any byte that does not fit is silently ignored. We could have extracted the slot 06174 * from the lock held by the current task, but that rendered the call from an isr impossible, so 06175 * you have to specify which queue you are using. Of course this call may not come 06176 * during the queue manipulation of some other task, but that is not possible due to the protection 06177 * of the privEnterSysCritical in other and this routine. */ 06178 privEnterSysCritical(); 06179 /* Tell what we are doing */ 06180 privTraceAPI(callIdGenQueuWrite); 06181 /* Check if the user uses this method properly. */ 06182 #if (cfgCheckMethodUse == cfgTrue) 06183 /* If we have no protection for the OS from interrupts ... */ 06184 #if (cfgIntOsProtected == cfgFalse) 06185 /* we may not arrive here from an isr */ 06186 if ((uiOsStatus & defContextGetMask) == defContextStateIsr) 06187 /* and if we do this is a fatal error. */ 06188 { privShowError((fatIllegalCallfromISR | errTaskStateNon), callIdGenQueuWrite, errNoInfo ); } 06189 #endif 06190 /* Check the capabilities of the current task */ 06191 privCheckCapabilities(callIdGenQueuWrite, ((cfgCapSynchronization) & 0xFF) ); 06192 /* The zero slot is reserved to indicate there is no lock, thus it cannot be actively used. */ 06193 if (uiSlot == defSlotFree) 06194 /* Report an error and stop the task. */ 06195 { privShowError((errSlotZeroUsed | errTaskStateCurrent), callIdGenQueuWrite, errCurrentTask ); } 06196 /* Check the type of the slot which is coupled to its number. */ 06197 if ((uiSlot < defNumberQueuBegin) || (uiSlot >= defNumberQueuEnd)) 06198 /* If so report an error. */ 06199 { privShowError((errSlotTypeMismatch | errTaskStateCurrent), callIdGenQueuWrite, errCurrentTask ); } 06200 #endif 06201 /* Get the write level of the queue, we put it in a register, cause gcc cannot optimize this variable for 06202 * it is volatile. Note that the queue number and the slot number differ by one, because the first item 06203 * on any array in C has the number zero. The first queue however is one, because we reserved number zero 06204 * to indicate a free lock. */ 06205 Tuint08 uiWrite = uiQueuWrite[uiSlot-1]; 06206 /* If the queue is already full we ignore the item, otherwise we may place it on the queue*/ 06207 if ((uiWrite & defQueuFillingGetMask) == defQueuFillingStateNotFull) 06208 { /* Get a pointer to the queue from flash. */ 06209 Tbyte * qCurQueu = portFlashReadWord(Tbyte *,pxQueulist[uiSlot-1]); 06210 /* writing is done downwards (this is because it is much easier to detect we reached the bottom of 06211 * an array as the top (this must be extracted from flash) so lower the writing level. */ 06212 uiWrite--; 06213 /* if we went trough the bottom ... */ 06214 if (uiWrite == 0xFF) 06215 { /* only then we need to access the flash to find the top of the array. */ 06216 uiWrite = privGetQueuSize(uiSlot-1)-1; } 06217 /* write the item (uiWrite points to the last item written). */ 06218 qCurQueu[uiWrite] = bItem; 06219 /* The queue can be full, and since this information is kept in a separate bit, we must test it 06220 * (of course after writing a byte the queue can never be empty thus equal read and write levels 06221 * must imply a full queue. ) */ 06222 if (uiWrite == uiQueuRead[uiSlot-1]) 06223 /* if so, write the full bit. */ 06224 { uiWrite = (uiWrite & defQueuFillingSetMask) | defQueuFillingStateFull; } 06225 /* restore the write level into the right place. */ 06226 uiQueuWrite[uiSlot-1] = uiWrite; } 06227 /* Sometime it may be useful to interpret writing to a full queue as an error */ 06228 #if (cfgCheckQueuFilling == cfgTrue) 06229 /* arriving here means we tried to write to a full queue, thus report the error, but this can 06230 * only be done when we are inside a task. From an ISR this is not possible because the error 06231 * cannot be reported and return. Furthermore, we do not know which task to terminate. This 06232 * function is not called from OS. */ 06233 else if ((uiOsStatus & defContextGetMask) == defContextStateTask) 06234 { privShowError((errQueuOverrun | errTaskStateCurrent), callIdGenQueuWrite, ((uiSlot << errInfoNumberShift) | errCurrentTask) ); } 06235 #endif 06236 /* We are done, leave the protected zone. */ 06237 privExitSysCritical(); } 06238 06239 #endif 06240 06241 06242 #if (cfgUseSynchronization != cfgSyncNon) && (defUseQueus == cfgTrue) && (includeGenQueuRead == cfgTrue) 06243 06244 Tbyte genQueuRead(Tuint08 uiSlot) 06245 { /* Use this method to get a byte on a queue. Usually you lock that queuee first by taskQueuRequest, so 06246 * you are sure you have full control over the queue and the byte you read will indeed be present on 06247 * the queue. However, you do not always have this possibility, for example if you are in an isr. 06248 * In that case you can obtain the number of present bytes with genQueuReadable or you can just 06249 * drain the queue. If the queue is empty subsequent calls to genQueuRead will return 0x00. We could 06250 * have extracted the slot from the lock held by the current task, but that rendered the call 06251 * from an isr impossible, so you have to specify which queue you are using. Of course this call may 06252 * not come during the queue manipulation of some other task, but that is not possible due to the 06253 * protection of the privEnterSysCritical in other and this routine. */ 06254 Tbyte Result; 06255 privEnterSysCritical(); 06256 /* Tell what we are doing */ 06257 privTraceAPI(callIdGenQueuRead); 06258 /* Check if the user uses this method properly. */ 06259 #if (cfgCheckMethodUse == cfgTrue) 06260 /* If we have no protection for the OS from interrupts ... */ 06261 #if (cfgIntOsProtected == cfgFalse) 06262 /* we may not arrive here from an isr */ 06263 if ((uiOsStatus & defContextGetMask) == defContextStateIsr) 06264 /* and if we do this is a fatal error. */ 06265 { privShowError((fatIllegalCallfromISR | errTaskStateNon), callIdGenQueuRead, errNoInfo ); } 06266 #endif 06267 /* Check the capabilities of the current task */ 06268 privCheckCapabilities(callIdGenQueuRead, ((cfgCapSynchronization) & 0xFF) ); 06269 /* The zero slot is reserved to indicate there is no lock, thus it cannot be actively used. */ 06270 if (uiSlot == defSlotFree) 06271 /* Report an error and stop the task. */ 06272 { privShowError((errSlotZeroUsed | errTaskStateCurrent), callIdGenQueuRead, errCurrentTask ); } 06273 /* Check the type of the slot which is coupled to its number. */ 06274 if ((uiSlot < defNumberQueuBegin) || (uiSlot >= defNumberQueuEnd)) 06275 /* If so report an error. */ 06276 { privShowError((errSlotTypeMismatch | errTaskStateCurrent), callIdGenQueuRead, errCurrentTask ); } 06277 #endif 06278 /* Get the read/write level of the queue, and put it in registers, cause gcc cannot optimize this 06279 * variable for they are volatile. Note that the queue number and the slot number differ by one, 06280 * because the first item on any array in C has the number zero. The first queue however is one, 06281 * because we reserved number zero to indicate a free lock. */ 06282 Tuint08 uiRead = uiQueuRead[uiSlot-1]; 06283 Tuint08 uiWrite = uiQueuWrite[uiSlot-1]; 06284 /* Check if the queue is not empty, if so there is no point in getting an item for the queue. 06285 * The queue is empty if the read and write levels are pointing to the same byte and the 06286 * queue is not full. */ 06287 if ((uiWrite != uiRead) || ((uiWrite & defQueuFillingGetMask) == defQueuFillingStateFull) ) 06288 { /* After reading a byte, the queue cannot be full anymore. We must actively remove the full 06289 * byte for elsewhere we use it to test if the queue is full without comparing the read and 06290 * write levels. */ 06291 uiQueuWrite[uiSlot-1] = (uiWrite & defQueuFillingSetMask) | defQueuFillingStateNotFull; 06292 /* Get a pointer to the queue from flash. */ 06293 Tbyte * qCurQueu = portFlashReadWord(Tbyte *,pxQueulist[uiSlot-1]); 06294 /* reading is done downwards (this is because it is much easier to detect we reached the bottom of 06295 * an array as the top (this must be extracted from flash) so lower the reading level. */ 06296 uiRead--; 06297 /* if we went trough the bottom ... */ 06298 if (uiRead == 0xFF) 06299 { /* only then we need to access the flash to find the top of the array. */ 06300 uiRead = privGetQueuSize(uiSlot-1)-1; } 06301 /* read the item (uiRead points to the last item written). */ 06302 Result = qCurQueu[uiRead]; 06303 /* restore the read level into the right place. */ 06304 uiQueuRead[uiSlot-1] = uiRead; } 06305 else 06306 { /* Sometimes it may be useful to interpret reading from an empty queue as an error */ 06307 #if (cfgCheckQueuFilling == cfgTrue) 06308 /* and arriving here means we tried to read from an empty queue, thus report the error, but this can 06309 * only be done when we are inside a task. From an ISR this is not possible because the error 06310 * cannot be reported and return. Furthermore, we do not know which task to terminate. This 06311 * function is not called from OS. */ 06312 if ((uiOsStatus & defContextGetMask) == defContextStateTask) 06313 { privShowError((errQueuUnderrun | errTaskStateCurrent), callIdGenQueuRead, ((uiSlot << errInfoNumberShift) | errCurrentTask) ); } 06314 #endif 06315 /* If we don't see it as an error, we must return something, so this is chosen to be 0x00. */ 06316 Result = 0x00; } 06317 /* We are done, leave the protected zone. */ 06318 privExitSysCritical(); 06319 /* and return the result. */ 06320 return Result; } 06321 06322 #endif 06323 06324 06325 #if (cfgUseSynchronization != cfgSyncNon) && (defUseQueus == cfgTrue) && (includeGenQueuClear == cfgTrue) 06326 06327 void genQueuClear(Tuint08 uiSlot) 06328 { /* Use this method to clear a queue. The method works, also if some other task is holding a lock 06329 * on this queue, so that is your own responsibility, you can use it inside a taskQueueRequest/taskQueuRelease 06330 * pair. The queue is not actually emptied, but the read/write levels are reset. Of course we act inside 06331 * a protected realm. */ 06332 privEnterSysCritical(); 06333 /* Tell what we are doing */ 06334 privTraceAPI(callIdGenQueuClear); 06335 /* Check if the user uses this method properly. */ 06336 #if (cfgCheckMethodUse == cfgTrue) 06337 /* If we have no protection for the OS from interrupts ... */ 06338 #if (cfgIntOsProtected == cfgFalse) 06339 /* we may not arrive here from an isr */ 06340 if ((uiOsStatus & defContextGetMask) == defContextStateIsr) 06341 /* and if we do this is a fatal error. */ 06342 { privShowError((fatIllegalCallfromISR | errTaskStateNon), callIdGenQueuClear, errNoInfo ); } 06343 #endif 06344 /* Check the capabilities of the current task */ 06345 privCheckCapabilities(callIdGenQueuClear, ((cfgCapSynchronization) & 0xFF) ); 06346 /* The zero slot is reserved to indicate there is no lock, thus it cannot be actively used. */ 06347 if (uiSlot == defSlotFree) 06348 /* Report an error and stop the task. */ 06349 { privShowError((errSlotZeroUsed | errTaskStateCurrent), callIdGenQueuClear, errCurrentTask ); } 06350 /* Check the type of the slot which is coupled to its number. */ 06351 if ((uiSlot < defNumberQueuBegin) || (uiSlot >= defNumberQueuEnd)) 06352 /* If so report an error. */ 06353 { privShowError((errSlotTypeMismatch | errTaskStateCurrent), callIdGenQueuClear, errCurrentTask ); } 06354 #endif 06355 /* Reset the read and write levels. Note that we are using constants here which can effectively only 06356 * be 0x00 since we also rely on clean queues to start with (there is no initializing needed before 06357 * a queue is used) and this cleaning is provided by the .bss cleaning section. */ 06358 uiQueuRead[uiSlot-1] = defQueuFillingReadEmpty; 06359 uiQueuWrite[uiSlot-1] = defQueuFillingWriteEmpty; 06360 /* Thats all folks. */ 06361 privExitSysCritical(); } 06362 06363 #endif 06364 06365 06366 #if (cfgUseSynchronization != cfgSyncNon) && (defUseQueus == cfgTrue) && (includeGenQueuPeek == cfgTrue) 06367 06368 Tbyte genQueuPeek(Tuint08 uiSlot) 06369 { /* Sometime is may be handy to look ahead in the queue. Use this method if you want to know which 06370 * byte is next. Of course, if more tasks are reading from a queue (bit odd, but still) an other 06371 * task could have read it before you can, so additional protection measure may be needed. */ 06372 Tbyte Result; 06373 /* we protect ourselves from other tasks. */ 06374 privEnterSysCritical(); 06375 /* Tell what we are doing */ 06376 privTraceAPI(callIdGenQueuPeek); 06377 /* Check if the user uses this method properly. */ 06378 #if (cfgCheckMethodUse == cfgTrue) 06379 /* If we have no protection for the OS from interrupts ... */ 06380 #if (cfgIntOsProtected == cfgFalse) 06381 /* we may not arrive here from an isr */ 06382 if ((uiOsStatus & defContextGetMask) == defContextStateIsr) 06383 /* and if we do this is a fatal error. */ 06384 { privShowError((fatIllegalCallfromISR | errTaskStateNon), callIdGenQueuPeek, errNoInfo ); } 06385 #endif 06386 /* Check the capabilities of the current task */ 06387 privCheckCapabilities(callIdGenQueuPeek, ((cfgCapSynchronization) & 0xFF) ); 06388 /* The zero slot is reserved to indicate there is no lock, thus it cannot be actively used. */ 06389 if (uiSlot == defSlotFree) 06390 /* Report an error and stop the task. */ 06391 { privShowError((errSlotZeroUsed | errTaskStateCurrent), callIdGenQueuPeek, errCurrentTask ); } 06392 /* Check the type of the slot which is coupled to its number. */ 06393 if ((uiSlot < defNumberQueuBegin) || (uiSlot >= defNumberQueuEnd)) 06394 /* If so report an error. */ 06395 { privShowError((errSlotTypeMismatch | errTaskStateCurrent), callIdGenQueuPeek, errCurrentTask ); } 06396 #endif 06397 /* Get a pointer to the queue from flash. */ 06398 Tbyte * qCurQueu = portFlashReadWord(Tbyte *,pxQueulist[uiSlot-1]); 06399 /* Get a pointer to the queue from flash. */ 06400 Tuint08 uiRead = uiQueuRead[uiSlot-1]; 06401 /* reading is done downwards (this is because it is much easier to detect we reached the bottom of 06402 * an array as the top (this must be extracted from flash) so lower the reading level. */ 06403 uiRead--; 06404 /* if we went trough the bottom ... */ 06405 if (uiRead == 0xFF) 06406 { /* only then we need to access the flash to find the top of the array. */ 06407 uiRead = privGetQueuSize(uiSlot-1)-1; } 06408 /* read the item (uiRead points to the last item written). */ 06409 Result = qCurQueu[uiRead]; 06410 /* Done, leave the protected realm */ 06411 privExitSysCritical(); 06412 /* and return the result. The queue itself is untouched. */ 06413 return Result; } 06414 06415 #endif 06416 06417 06418 #if (cfgUseSynchronization != cfgSyncNon) && (defUseQueus == cfgTrue) && (includeGenQueuReadable == cfgTrue) 06419 06420 Tuint08 genQueuReadable(Tuint08 uiSlot) 06421 { /* Use this method to see how many bytes can be read from the queue */ 06422 Tuint08 Result; 06423 /* we protect ourselves from other tasks. */ 06424 privEnterSysCritical(); 06425 /* Tell what we are doing */ 06426 privTraceAPI(callIdGenQueuReadable); 06427 /* Check if the user uses this method properly. */ 06428 #if (cfgCheckMethodUse == cfgTrue) 06429 /* If we have no protection for the OS from interrupts ... */ 06430 #if (cfgIntOsProtected == cfgFalse) 06431 /* we may not arrive here from an isr */ 06432 if ((uiOsStatus & defContextGetMask) == defContextStateIsr) 06433 /* and if we do this is a fatal error. */ 06434 { privShowError((fatIllegalCallfromISR | errTaskStateNon), callIdGenQueuReadable, errNoInfo ); } 06435 #endif 06436 /* Check the capabilities of the current task */ 06437 privCheckCapabilities(callIdGenQueuReadable, ((cfgCapSynchronization) & 0xFF) ); 06438 /* The zero slot is reserved to indicate there is no lock, thus it cannot be actively used. */ 06439 if (uiSlot == defSlotFree) 06440 /* Report an error and stop the task. */ 06441 { privShowError((errSlotZeroUsed | errTaskStateCurrent), callIdGenQueuReadable, errCurrentTask ); } 06442 /* Check the type of the slot which is coupled to its number. */ 06443 if ((uiSlot < defNumberQueuBegin) || (uiSlot >= defNumberQueuEnd)) 06444 /* If so report an error. */ 06445 { privShowError((errSlotTypeMismatch | errTaskStateCurrent), callIdGenQueuReadable, errCurrentTask ); } 06446 #endif 06447 /* Get the number of bytes on the queue */ 06448 Result = privQueuTest(uiSlot,+1); 06449 /* Done, leave the protected realm */ 06450 privExitSysCritical(); 06451 /* and return the result. The queue itself is untouched. */ 06452 return Result; } 06453 06454 #endif 06455 06456 06457 #if (cfgUseSynchronization != cfgSyncNon) && (defUseQueus == cfgTrue) && (includeGenQueuWriteable == cfgTrue) 06458 06459 Tuint08 genQueuWriteable(Tuint08 uiSlot) 06460 { /* Use this method to see how many bytes can be written to the queue */ 06461 Tuint08 Result; 06462 /* we protect ourselves from other tasks. */ 06463 privEnterSysCritical(); 06464 /* Tell what we are doing */ 06465 privTraceAPI(callIdGenQueuWriteable); 06466 /* Check if the user uses this method properly. */ 06467 #if (cfgCheckMethodUse == cfgTrue) 06468 /* If we have no protection for the OS from interrupts ... */ 06469 #if (cfgIntOsProtected == cfgFalse) 06470 /* we may not arrive here from an isr */ 06471 if ((uiOsStatus & defContextGetMask) == defContextStateIsr) 06472 /* and if we do this is a fatal error. */ 06473 { privShowError((fatIllegalCallfromISR | errTaskStateNon), callIdGenQueuWriteable, errNoInfo ); } 06474 #endif 06475 /* Check the capabilities of the current task */ 06476 privCheckCapabilities(callIdGenQueuWriteable, ((cfgCapSynchronization) & 0xFF) ); 06477 /* The zero slot is reserved to indicate there is no lock, thus it cannot be actively used. */ 06478 if (uiSlot == defSlotFree) 06479 /* Report an error and stop the task. */ 06480 { privShowError((errSlotZeroUsed | errTaskStateCurrent), callIdGenQueuWriteable, errCurrentTask ); } 06481 /* Check the type of the slot which is coupled to its number. */ 06482 if ((uiSlot < defNumberQueuBegin) || (uiSlot >= defNumberQueuEnd)) 06483 /* If so report an error. */ 06484 { privShowError((errSlotTypeMismatch | errTaskStateCurrent), callIdGenQueuWriteable, errCurrentTask ); } 06485 #endif 06486 /* Get the number of free bytes of the queue */ 06487 Result = privQueuTest(uiSlot,-1); 06488 /* Done, leave the protected realm */ 06489 privExitSysCritical(); 06490 /* and return the result. The queue itself is untouched. */ 06491 return Result; } 06492 06493 #endif 06494 06495 06496 #if (cfgUseSynchronization != cfgSyncNon) && (defUseQueus == cfgTrue) && (includeGenQueuFull == cfgTrue) 06497 06498 Tbool genQueuFull(Tuint08 uiSlot) 06499 { /* Use this method to see if the queue is full. The queue itself may change directly after the call, 06500 * but if you are the only one writing, you can be sure the queue is not full after this call 06501 * when it returns false. We protect ourselves from other tasks. */ 06502 privEnterSysCritical(); 06503 /* Tell what we are doing */ 06504 privTraceAPI(callIdGenQueuFull); 06505 /* Check if the user uses this method properly. */ 06506 #if (cfgCheckMethodUse == cfgTrue) 06507 /* If we have no protection for the OS from interrupts ... */ 06508 #if (cfgIntOsProtected == cfgFalse) 06509 /* we may not arrive here from an isr */ 06510 if ((uiOsStatus & defContextGetMask) == defContextStateIsr) 06511 /* and if we do this is a fatal error. */ 06512 { privShowError((fatIllegalCallfromISR | errTaskStateNon), callIdGenQueuFull, errNoInfo ); } 06513 #endif 06514 /* Check the capabilities of the current task */ 06515 privCheckCapabilities(callIdGenQueuFull, ((cfgCapSynchronization) & 0xFF) ); 06516 /* The zero slot is reserved to indicate there is no lock, thus it cannot be actively used. */ 06517 if (uiSlot == defSlotFree) 06518 /* Report an error and stop the task. */ 06519 { privShowError((errSlotZeroUsed | errTaskStateCurrent), callIdGenQueuFull, errCurrentTask ); } 06520 /* Check the type of the slot which is coupled to its number. */ 06521 if ((uiSlot < defNumberQueuBegin) || (uiSlot >= defNumberQueuEnd)) 06522 /* If so report an error. */ 06523 { privShowError((errSlotTypeMismatch | errTaskStateCurrent), callIdGenQueuFull, errCurrentTask ); } 06524 #endif 06525 /* Get the write level and extract the full bit. */ 06526 Tbool Result = (uiQueuWrite[uiSlot-1] & defQueuFillingGetMask) == defQueuFillingStateFull; 06527 /* Done, leave the protected realm */ 06528 privExitSysCritical(); 06529 /* and return the result. The queue itself is untouched. */ 06530 return Result; } 06531 06532 #endif 06533 06534 #if (cfgUseSynchronization != cfgSyncNon) && (defUseQueus == cfgTrue) && (includeGenQueuEmpty == cfgTrue) 06535 06536 Tbool genQueuEmpty(Tuint08 uiSlot) 06537 { /* Use this method to see if the queue is empty. Protect is needed in this case, since there is no 06538 * empty bit that can be read atomically. The queue itself may change directly after the call, but 06539 * if you are the only one reading, you can be sure the queue is not empty after this call when 06540 * it returns false. */ 06541 Tuint08 Result; 06542 /* we protect ourselves from other tasks. */ 06543 privEnterSysCritical(); 06544 /* Tell what we are doing */ 06545 privTraceAPI(callIdGenQueuEmpty); 06546 /* Check if the user uses this method properly. */ 06547 #if (cfgCheckMethodUse == cfgTrue) 06548 /* If we have no protection for the OS from interrupts ... */ 06549 #if (cfgIntOsProtected == cfgFalse) 06550 /* we may not arrive here from an isr */ 06551 if ((uiOsStatus & defContextGetMask) == defContextStateIsr) 06552 /* and if we do this is a fatal error. */ 06553 { privShowError((fatIllegalCallfromISR | errTaskStateNon), callIdGenQueuEmpty, errNoInfo ); } 06554 #endif 06555 /* Check the capabilities of the current task */ 06556 privCheckCapabilities(callIdGenQueuEmpty, ((cfgCapSynchronization) & 0xFF) ); 06557 /* The zero slot is reserved to indicate there is no lock, thus it cannot be actively used. */ 06558 if (uiSlot == defSlotFree) 06559 /* Report an error and stop the task. */ 06560 { privShowError((errSlotZeroUsed | errTaskStateCurrent), callIdGenQueuEmpty, errCurrentTask ); } 06561 /* Check the type of the slot which is coupled to its number. */ 06562 if ((uiSlot < defNumberQueuBegin) || (uiSlot >= defNumberQueuEnd)) 06563 /* If so report an error. */ 06564 { privShowError((errSlotTypeMismatch | errTaskStateCurrent), callIdGenQueuEmpty, errCurrentTask ); } 06565 #endif 06566 /* We need both levels to determine is the queue is empty. */ 06567 Tuint08 uiRead = uiQueuRead[uiSlot-1]; 06568 Tuint08 uiWrite = uiQueuWrite[uiSlot-1]; 06569 /* The queue is empty if the read and write levels are pointing to the same byte and the 06570 * queue is not full. */ 06571 Result = ((uiWrite == uiRead) && ((uiWrite & defQueuFillingGetMask) == defQueuFillingStateNotFull) ); 06572 /* Done, leave the protected realm */ 06573 privExitSysCritical(); 06574 /* and return the result. The queue itself is untouched. */ 06575 return Result; } 06576 06577 #endif 06578 06579 06580 #if (cfgUseFileSystem == cfgTrue) 06581 06582 void privWaitForFsAccessBody(void) 06583 { /* Call this if you want to wait (block) until you may write. This method cannot be called 06584 * from the outside although it is a 'body' function. It is used to call from the inside 06585 * of api functions. 06586 * (See the explanation of the design with 'body functions' design elsewhere.) */ 06587 privInitOsSwitch(); 06588 /* Tell we can not burn again. */ 06589 privTrace(traceBurnLock); 06590 /* We always want to let the current task wait for access. */ 06591 TtaskControlBlock * curTCB = privTcbList(privTaskNumber(defCurrentTaskNumber)); 06592 /* A dominant task may usually not block. But this is a block that is not held by an other 06593 * task, and therefore cannot deadlock the system, we can therefore wait here, within the 06594 * OS space, for the lock to expire. */ 06595 #if ((includeTaskProtectSwitchTasks == cfgTrue) || (includeTaskProtectSwitchCritical == cfgTrue)) 06596 /* If we have dominant task at hand, so other tasks need no attention. */ 06597 if ((curTCB->uiTaskStatus & defBaseDressGetMask) == defBaseDressRunable) 06598 { /* Spin lock on the burn lock test, if present. */ 06599 while (!portFSWriteReady()); 06600 /* The file system is accessible again, continue the task. */ 06601 privEnterOS(defActionTaskStateKeep); } 06602 else 06603 #endif 06604 { /* We block without delay (this action cannot timeout, for it is not realistic to time out) */ 06605 curTCB->uiTaskStatus = (curTCB->uiTaskStatus & (defBaseFileBlockedSetMask & defBaseDressSetMask)) | (defBaseFileBlockedTask | defBaseDressWrite); 06606 /* While we are waiting, we set the burn block bit. In the main OS loop, the real 06607 * burn state of the device is checked, and as long as it prohibits writing, 06608 * this bit stays activated. Test before writing. */ 06609 uiFsStatus = ((uiFsStatus & defFsBurnBlockSetMask) | defFsBurnBlockActive); 06610 /* Done, and since this method is meant to block, we must switch. */ 06611 privEnterOS(defActionTaskStateSwitch); } } 06612 06613 #endif 06614 06615 06616 #if (cfgUseFileSystem == cfgTrue) && (includeTaskFileAccess == cfgTrue) 06617 06618 #if (cfgUseTimeout == cfgTrue) 06619 #if (cfgUseFileSystemConcurrentRead == cfgTrue) 06620 void privFileOpenBody(Tbool bReadOnly, Tuint16 uiTicksToWait) 06621 #else 06622 void privFileOpenBody(Tuint16 uiTicksToWait) 06623 #endif 06624 #else 06625 #if (cfgUseFileSystemConcurrentRead == cfgTrue) 06626 void privFileOpenBody(Tbool bReadOnly) 06627 #else 06628 void privFileOpenBody(void) 06629 #endif 06630 #endif 06631 { /* Call this if you want to open a file. The function is present in two flavours. One 06632 * standard, and one if you want to make use of single writing, simultaneous reading. */ 06633 privInitOsSwitch(); 06634 /* Tell what we are doing */ 06635 privTraceAPI(callIdTaskFileOpen); 06636 /* For some operations we need the current task control block */ 06637 #if (defUseFsField == cfgTrue) || (defUseFsOnMultipleTasks == cfgTrue) || (cfgCheckMethodUse == cfgTrue) 06638 TtaskControlBlock * curTCB = privTcbList(privTaskNumber(defCurrentTaskNumber)); 06639 #endif 06640 /* Check if the user uses this method properly. */ 06641 #if (cfgCheckMethodUse == cfgTrue) 06642 /* Check the capabilities of the current task */ 06643 privCheckCapabilities(callIdTaskFileOpen, ((cfgCapFileSystem) & 0xFF) ); 06644 /* A dominant task may not open a file if an other task may be holding the file system, this 06645 * may cause a permanent deadlock. In case there is only one task using the file system, there 06646 * is no problem. */ 06647 #if (defUseFsOnMultipleTasks == cfgTrue) && ((includeTaskProtectSwitchTasks == cfgTrue) || (includeTaskProtectSwitchCritical == cfgTrue)) 06648 /* And that is to see if we do not have a dominant task at hand */ 06649 if ((curTCB->uiTaskStatus & defBaseDressGetMask) == defBaseDressRunable) 06650 /* Report an error and stop the task. */ 06651 { privShowError((errIllegalDominantState | errTaskStateCurrent | errOsStateAsIs), callIdTaskFileOpen, errCurrentTask ); } 06652 #endif 06653 /* Opening is not allowed if we are allready open */ 06654 if ((curTCB->defFsField & (defFsReadGetMask | defFsWriteGetMask)) != ( defFsReadClear | defFsWriteClear ) ) 06655 /* Report an error and stop the task. */ 06656 { privShowError((errFileOpenMode | errTaskStateCurrent | errOsStateAsIs), callIdTaskFileOpen, errCurrentTask ); } 06657 /* In case we allow for timeouts there are some more checks. */ 06658 #if (cfgUseTimeout == cfgTrue) 06659 /* Check the capabilities of the current task */ 06660 privCheckCapabilities(callIdTaskFileOpen, ((cfgCapTimeout) & 0xFF) ); 06661 /* Check if we do not violate the max delay time */ 06662 if (uiTicksToWait > defDelayTimeMax) 06663 /* Report an error and stop the task. */ 06664 { privShowError((errTaskDelayTooLong | errTaskStateCurrent | errOsStateAsIs), callIdTaskFileOpen, errCurrentTask ); } 06665 #endif 06666 #endif 06667 /* If we make use of timeouts, we write it as a delay. */ 06668 #if (cfgUseTimeout == cfgTrue) 06669 /* If we make use of timeouts, set the delay variable, which is used for the timeout. */ 06670 if (uiTicksToWait != defLockBlockInfinite) { privDelayCalcFromNow(uiTicksToWait); } 06671 #endif 06672 /* Check if we make use of simultaneous reads. */ 06673 #if (cfgUseFileSystemConcurrentRead == cfgTrue) 06674 if (bReadOnly) 06675 { /* The user opens the file in the read only mode */ 06676 #if (defUseFsField == cfgTrue) 06677 /* Write the read mode in the field. */ 06678 curTCB->defFsField = (curTCB->defFsField & defFsReadSetMask) | defFsReadActive; 06679 #endif 06680 /* If we have only one task using the file system it makes no sense to block, access is 06681 * always possible. */ 06682 #if (defUseFsOnMultipleTasks == cfgTrue) 06683 /* The way this works is that we always block, and subsequently see which task can be 06684 * freed. If the current task is the only one, this generates a little more overhead, 06685 * but save a lot of bytes from the code. */ 06686 curTCB->uiTaskStatus = (curTCB->uiTaskStatus & (defBaseFileBlockedSetMask & defBaseDressSetMask)) | (defBaseFileBlockedTask | defBaseDressRead); 06687 #else 06688 /* But we have to set that we are reading. This is not needed in case we are blocking, since then it 06689 * will be done in the privReleaseFileBlocks handling. In fact, it would be plain wrong. */ 06690 uiFsStatus = (uiFsStatus & defFsReadBlockSetMask) | defFsReadBlockActive; 06691 #endif 06692 } 06693 else 06694 #endif 06695 { /* If we want to write and read, we must issue a write lock*/ 06696 #if (defUseFsField == cfgTrue) 06697 /* Making use of the fields required setting the writemode. We use this typically if we allow for 06698 * sleeping tasks, or the possibility to terminate and recreate tasks. Also, if we have the checkmodus 06699 * switched on, we need this information. */ 06700 curTCB->defFsField = (curTCB->defFsField & defFsWriteSetMask) | defFsWriteActive; 06701 #endif 06702 /* If we have only one task using the file system it makes no sense to block, access is 06703 * always possible. */ 06704 #if (defUseFsOnMultipleTasks == cfgTrue) 06705 /* The way this works is that we always block, and subsequently see which task can be 06706 * freed. If the current task is the only one, this generates a little more overhead, 06707 * but save a lot of bytes from the code. */ 06708 curTCB->uiTaskStatus = (curTCB->uiTaskStatus & (defBaseFileBlockedSetMask & defBaseDressSetMask)) | (defBaseFileBlockedTask | defBaseDressWrite); 06709 #else 06710 /* But we have to set that we are writing. This is not needed in case we are blocking, since then it 06711 * will be done in the privReleaseFileBlocks handling. In fact, it would be plain wrong. */ 06712 uiFsStatus = (uiFsStatus & defFsWriteBlockSetMask) | defFsWriteBlockActive; 06713 #endif 06714 } 06715 /* If we have only one task using the file system we do not block on entry, so there is 06716 * nothing to release right now. */ 06717 #if (defUseFsOnMultipleTasks == cfgTrue) 06718 /* Check if anything must be released, which is quite likely, since often this will be the only 06719 * task asking for a lock. */ 06720 privReleaseFileBlocks(); 06721 #endif 06722 /* Done, since this block may be kept, we must require a switch. (In case of a dominant task 06723 * this will have no effect.) */ 06724 privEnterOS(defActionTaskStateSwitch); } 06725 06726 #endif 06727 06728 06729 #if (cfgUseFileSystem == cfgTrue) && (includeTaskFileAccess == cfgTrue) 06730 06731 void privFileCloseBody(void) 06732 { /* Call this if you want to close a file. It should be called from the task 06733 * that is actually closing a file, for it is assuming the current task holds 06734 * the lock. If the call returns all reading or wrting actions have come to 06735 * an end, and no burnlocks are active. The call may block.*/ 06736 privInitOsSwitch(); 06737 /* Tell what we are doing */ 06738 privTraceAPI(callIdTaskFileClose); 06739 /* Check if the user uses this method properly. */ 06740 #if (cfgCheckMethodUse == cfgTrue) 06741 /* Check the capabilities of the current task */ 06742 privCheckCapabilities(callIdTaskFileClose, ((cfgCapFileSystem) & 0xFF) ); 06743 /* Get the tack control block */ 06744 TtaskControlBlock * curTCB = privTcbList(privTaskNumber(defCurrentTaskNumber)); 06745 /* Closing is not allowed if we are not open */ 06746 if ((curTCB->defFsField & (defFsReadGetMask | defFsWriteGetMask)) == ( defFsReadClear | defFsWriteClear ) ) 06747 /* Report an error and stop the task. */ 06748 { privShowError((errFileClosedMode | errTaskStateCurrent | errOsStateAsIs), callIdTaskFileClose, errCurrentTask ); } 06749 #endif 06750 /* Ask for closing the file. Upon return the file is closed if it was reading, but if 06751 * the task was writing, the call returns with a write release request, and the actual 06752 * closing is done in the main loop. */ 06753 privPrepareFileClose(privTaskNumber(defCurrentTaskNumber)); 06754 /* Done lets switch to be certain. */ 06755 privEnterOS(defActionTaskStateSwitch); } 06756 06757 #endif 06758 06759 06760 #if (cfgUseFileSystem == cfgTrue) && (cfgCheckMethodUse == cfgTrue) 06761 06762 static void privCheckFileSpecsWriting(Tuint08 uiFileNumber, Tuint08 uiOffset, Tuint08 uiSize, Tuint08 uiCallId) 06763 { /* Get the tack control block */ 06764 TtaskControlBlock * curTCB = privTcbList(privTaskNumber(defCurrentTaskNumber)); 06765 /* Setting size is not allowed if we are not open in write mode */ 06766 if ((curTCB->defFsField & defFsWriteGetMask) == defFsWriteClear) 06767 /* Report an error and stop the task. */ 06768 { privShowError((errFileWrongMode | errTaskStateCurrent), uiCallId, errCurrentTask ); } 06769 /* Check if we have a valid file number */ 06770 if (uiFileNumber >= defFsNumberOfAllFiles) 06771 /* Report an error and stop the task. */ 06772 { privShowError((errFileInvalidFileNumber | errTaskStateCurrent), uiCallId, errCurrentTask ); } 06773 /* Get the maximal size of file */ 06774 Tuint08 uiFileSizeMax = privFileSpace(uiFileNumber); 06775 /* If we have length information ...*/ 06776 #if (cfgUseFileSystemMaintainFAT == cfgTrue) 06777 /* ... get the actual length of the file*/ 06778 Tuint08 uiFileSizeActual = (Tuint08) portFSReadByte((Taddress) (Tuint16) uiFileNumber); 06779 #else 06780 /* ... if not, we just compare with the maximal file size. */ 06781 Tuint08 uiFileSizeActual = uiFileSizeMax; 06782 #endif 06783 /* Now, we have the following to check 06784 * reading 0 <= Offset <= ActualLength AND 0 <= Offset+Size <= ActualLength 06785 * writing 0 <= Offset <= ActualLength AND 0 <= Offset+Size <= AvailableSpace 06786 * Note that at writing we may start after the last byte, but not at reading, except if we read zero bytes. 06787 * In case we do not have length information we simply set ActualLength:=AvailableSpace. 06788 * Of course we assume ActualLength <= AvailableSpace. If not, we should have detected that earlier. 06789 * Note that we must rearrange the calculations to stay within the 8 bit datasize. */ 06790 /* Here we are writing.*/ 06791 if ((uiOffset > uiFileSizeActual) || (uiSize > (uiFileSizeMax - uiOffset) )) 06792 /* Report an error and stop the task. */ 06793 { privShowError((errFileOutOfRange | errTaskStateCurrent), uiCallId, errCurrentTask ); } } 06794 06795 #endif 06796 06797 06798 #if (cfgUseFileSystem == cfgTrue) && (cfgCheckMethodUse == cfgTrue) 06799 06800 static void privCheckFileSpecsReading(Tuint08 uiFileNumber, Tuint08 uiOffset, Tuint08 uiSize, Tuint08 uiCallId) 06801 { /* Get the tack control block */ 06802 TtaskControlBlock * curTCB = privTcbList(privTaskNumber(defCurrentTaskNumber)); 06803 /* Getting the size is not allowed if we are not open */ 06804 if ((curTCB->defFsField & (defFsReadGetMask | defFsWriteGetMask)) == ( defFsReadClear | defFsWriteClear ) ) 06805 /* Report an error and stop the task. */ 06806 { privShowError((errFileClosedMode | errTaskStateCurrent), uiCallId, errCurrentTask ); } 06807 /* Check if we have a valid file number */ 06808 if (uiFileNumber >= defFsNumberOfAllFiles) 06809 /* Report an error and stop the task. */ 06810 { privShowError((errFileInvalidFileNumber | errTaskStateCurrent), uiCallId, errCurrentTask ); } 06811 /* If we have length information ...*/ 06812 #if (cfgUseFileSystemMaintainFAT == cfgTrue) 06813 /* ... get the actual length of the file*/ 06814 Tuint08 uiFileSizeActual = (Tuint08) portFSReadByte((Taddress) (Tuint16) uiFileNumber); 06815 #else 06816 /* ... if not, we just compare with the maximal file size. */ 06817 Tuint08 uiFileSizeActual = privFileSpace(uiFileNumber); 06818 #endif 06819 /* Now, we have the following to check 06820 * reading 0 <= Offset <= ActualLength AND 0 <= Offset+Size <= ActualLength 06821 * writing 0 <= Offset <= ActualLength AND 0 <= Offset+Size <= AvailableSpace 06822 * Note that at writing we may start after the last byte, but not at reading, except if we read zero bytes. 06823 * In case we do not have length information we simply set ActualLength:=AvailableSpace. 06824 * Of course we assume ActualLength <= AvailableSpace. If not, we should have detected that earlier. 06825 * Note that we must rearrange the calculations to stay within the 8 bit datasize. */ 06826 /* Here we are reading.*/ 06827 if ((uiOffset > uiFileSizeActual) || (uiSize > (uiFileSizeActual - uiOffset) )) 06828 /* Report an error and stop the task. */ 06829 { privShowError((errFileOutOfRange | errTaskStateCurrent), uiCallId, errCurrentTask ); } } 06830 06831 06832 06833 #endif 06834 06835 #if (cfgUseFileSystem == cfgTrue) && (cfgUseFileSystemMaintainFAT == cfgTrue) && (includeTaskFileSetSize == cfgTrue) 06836 06837 void taskFileSetSize(Tuint08 uiFileNumber, Tuint08 uiSize) 06838 { /* Call this if you want adjust the size of a file or to clear a file. Only call it inside 06839 * fileOpen/fileClose construct. Note that this method is interruptable by a tick interrupt. 06840 * The file is not actually cleared or changed but the length is simply set to a new value. 06841 * If you need to really clear a file, fill it with zero's manually. */ 06842 #if (cfgCheckTrace == cfgTrue) || (cfgCheckMethodUse == cfgTrue) 06843 /* We need protection for the maintenance functions. */ 06844 privEnterSysCritical(); 06845 #endif 06846 /* Tell what we are doing */ 06847 privTraceAPI(callIdTaskFileSetSize); 06848 /* Check the use of this call.*/ 06849 #if (cfgCheckMethodUse == cfgTrue) 06850 /* Check the capabilities of the current task */ 06851 privCheckCapabilities(callIdTaskFileSetSize, ((cfgCapFileSystem) & 0xFF) ); 06852 /* Check if the parameters are such that operations stay within the filespace and are sensible. */ 06853 privCheckFileSpecsWriting(uiFileNumber,0,uiSize,callIdTaskFileSetSize); 06854 #endif 06855 #if (cfgCheckTrace == cfgTrue) || (cfgCheckMethodUse == cfgTrue) 06856 /* Here we can switch of that protection */ 06857 privExitSysCritical(); 06858 #endif 06859 /* Set the length of the file. Since the length info is at the start of the filespace, 06860 * we can just cast the filenumber to an address. Writing the new length is all to do. */ 06861 portFSWriteByte(((Taddress) (Tuint16) uiFileNumber),uiSize); 06862 /* Wait until the write is over. The privWaitForFsAccess() blocks until 06863 * the burnlock has been cleared. */ 06864 privWaitForFsAccess(); } 06865 06866 #endif 06867 06868 06869 #if (cfgUseFileSystem == cfgTrue) && (cfgUseFileSystemMaintainFAT == cfgTrue) && (includeTaskFileGetSize == cfgTrue) 06870 06871 Tuint08 taskFileGetSize(Tuint08 uiFileNumber) 06872 { /* Call this if you know the size of a file. Only call it inside fileOpen/fileClose construct. 06873 * Note that this method is interruptable by a tick interrupt.*/ 06874 #if (cfgCheckTrace == cfgTrue) || (cfgCheckMethodUse == cfgTrue) 06875 /* We need protection for the maintenance functions. */ 06876 privEnterSysCritical(); 06877 #endif 06878 /* Tell what we are doing */ 06879 privTraceAPI(callIdTaskFileGetSize); 06880 /* Check if the user uses this method properly. */ 06881 #if (cfgCheckMethodUse == cfgTrue) 06882 /* Check the capabilities of the current task */ 06883 privCheckCapabilities(callIdTaskFileGetSize, ((cfgCapFileSystem) & 0xFF) ); 06884 /* Check if the parameters are such that operations stay within the filespace and are sensible. */ 06885 privCheckFileSpecsReading(uiFileNumber,0,0,callIdTaskFileGetSize); 06886 #endif 06887 #if (cfgCheckTrace == cfgTrue) || (cfgCheckMethodUse == cfgTrue) 06888 /* Here we can switch of that protection */ 06889 privExitSysCritical(); 06890 #endif 06891 /* Return the length of the file. Since the length info is at the start of the filespace, 06892 * we can just cast the filenumber to an address. */ 06893 return (Tuint08) portFSReadByte((Taddress) (Tuint16) uiFileNumber); } 06894 06895 #endif 06896 06897 06898 #if (cfgUseFileSystem == cfgTrue) && (includeTaskFileFormat == cfgTrue) 06899 06900 void taskFileFormat(void) 06901 { /* Call this if you want to set all bytes from the filesystem to zero. Only call it inside 06902 * fileOpen/fileClose construct. Note that this method is interruptable by a tick interrupt.*/ 06903 #if (cfgCheckTrace == cfgTrue) || (cfgCheckMethodUse == cfgTrue) 06904 /* We need protection for the maintenance functions. */ 06905 privEnterSysCritical(); 06906 #endif 06907 /* Tell what we are doing */ 06908 privTraceAPI(callIdTaskFileFormat); 06909 /* Check if the user uses this method properly. */ 06910 #if (cfgCheckMethodUse == cfgTrue) 06911 /* Check the capabilities of the current task */ 06912 privCheckCapabilities(callIdTaskFileFormat, ((cfgCapFileSystem) & 0xFF) ); 06913 /* Get the tack control block */ 06914 TtaskControlBlock * curTCB = privTcbList(privTaskNumber(defCurrentTaskNumber)); 06915 /* Formatting the file system is not allowed if we are not open in the write mode */ 06916 if ((curTCB->defFsField & defFsWriteGetMask) == defFsWriteClear) 06917 /* Report an error and stop the task. */ 06918 { privShowError((errFileWrongMode | errTaskStateCurrent), callIdTaskFileFormat, errCurrentTask ); } 06919 #endif 06920 #if (cfgCheckTrace == cfgTrue) || (cfgCheckMethodUse == cfgTrue) 06921 /* Here we can switch of that protection */ 06922 privExitSysCritical(); 06923 #endif 06924 /* Loop through all bytes and clean them */ 06925 Tuint16 uiLoopBytes; 06926 for(uiLoopBytes=0; uiLoopBytes<defTotalAllFileSpace; uiLoopBytes++) 06927 { /* Wait until we may write. We do not ask if the burnlock is present, for it most certainly 06928 * is, directly after a write operation. */ 06929 privWaitForFsAccess(); 06930 /* Get the bytes from the pipe and write them to the file system. */ 06931 portFSWriteByte((Taddress) uiLoopBytes,0); } 06932 /* Wait until we are finished writing. */ 06933 privWaitForFsAccess(); } 06934 06935 #endif 06936 06937 06938 #if (cfgUseFileSystem == cfgTrue) && (includeTaskFileReadByte == cfgTrue) 06939 06940 Tbyte taskFileReadByte(Tuint08 uiFileNumber, Tuint08 uiOffset) 06941 { /* Call this if you to read a byte from the file. You have 'raw access' 06942 * and can read beyond the end of the file. Only call it inside fileOpen/fileClose 06943 * construct. Note that this method is interruptible by a tick interrupt.*/ 06944 #if (cfgCheckTrace == cfgTrue) || (cfgCheckMethodUse == cfgTrue) 06945 /* We need protection for the maintenance functions. */ 06946 privEnterSysCritical(); 06947 #endif 06948 /* Tell what we are doing */ 06949 privTraceAPI(callIdTaskFileReadByte); 06950 /* Check if the user uses this method properly. */ 06951 #if (cfgCheckMethodUse == cfgTrue) 06952 /* Check the capabilities of the current task */ 06953 privCheckCapabilities(callIdTaskFileReadByte, ((cfgCapFileSystem) & 0xFF) ); 06954 /* Check if the parameters are such that operations stay within the filespace and are sensible. */ 06955 privCheckFileSpecsReading(uiFileNumber,uiOffset,1,callIdTaskFileReadByte); 06956 #endif 06957 #if (cfgCheckTrace == cfgTrue) || (cfgCheckMethodUse == cfgTrue) 06958 /* Here we can switch of that protection */ 06959 privExitSysCritical(); 06960 #endif 06961 /* Get the location of the byte that must be read. */ 06962 Taddress pFileLoc = privFileLocation(uiFileNumber,uiOffset); 06963 /* Read the byte and return the value */ 06964 return (Tuint08) portFSReadByte(pFileLoc); } 06965 06966 #endif 06967 06968 06969 #if (cfgUseFileSystem == cfgTrue) && (includeTaskFileWriteByte == cfgTrue) 06970 06971 void taskFileWriteByte(Tuint08 uiFileNumber, Tuint08 uiOffset, Tbyte bItem) 06972 { /* Call this if you to write a byte to the file. You have 'raw access' 06973 * and can write beyond the end of the file. Length info is not maintained. 06974 * Only call it inside fileOpen/fileClose 06975 * construct. Note that this method is interruptible by a tick interrupt.*/ 06976 #if (cfgCheckTrace == cfgTrue) || (cfgCheckMethodUse == cfgTrue) 06977 /* We need protection for the maintenance functions. */ 06978 privEnterSysCritical(); 06979 #endif 06980 /* Tell what we are doing */ 06981 privTraceAPI(callIdTaskFileWriteByte); 06982 /* Check if the user uses this method properly. */ 06983 #if (cfgCheckMethodUse == cfgTrue) 06984 /* Check the capabilities of the current task */ 06985 privCheckCapabilities(callIdTaskFileWriteByte, ((cfgCapFileSystem) & 0xFF) ); 06986 /* Check if the parameters are such that operations stay within the filespace and are sensible. */ 06987 privCheckFileSpecsWriting(uiFileNumber,uiOffset,1,callIdTaskFileWriteByte); 06988 #endif 06989 #if (cfgCheckTrace == cfgTrue) || (cfgCheckMethodUse == cfgTrue) 06990 /* Here we can switch of that protection */ 06991 privExitSysCritical(); 06992 #endif 06993 /* Get the location of the byte that must be written. */ 06994 Taddress pFileLoc = privFileLocation(uiFileNumber,uiOffset); 06995 /* write the value, it is assumed any burnlocks are gone. */ 06996 portFSWriteByte(pFileLoc,bItem); 06997 /* Wait until the write is over. The privWaitForFsAccess() blocks until 06998 * the burnlock has been cleared. */ 06999 privWaitForFsAccess(); } 07000 07001 #endif 07002 07003 07004 #if (cfgUseFileSystem == cfgTrue) && (cfgUseFileSystemMaintainFAT == cfgTrue) && (includeTaskFileAppendByte == cfgTrue) 07005 07006 void taskFileAppendByte(Tuint08 uiFileNumber, Tbyte bItem) 07007 { /* Call this if you to write one byte to the end of the file. If you 07008 * pass the end the byte is written at the start. Use as ringbuffer. 07009 * Only call it inside fileOpen/fileClose */ 07010 #if (cfgCheckTrace == cfgTrue) || (cfgCheckMethodUse == cfgTrue) 07011 /* We need protection for the maintenance functions. */ 07012 privEnterSysCritical(); 07013 #endif 07014 /* Tell what we are doing */ 07015 privTraceAPI(callIdTaskFileAppendByte); 07016 /* Check if the user uses this method properly. */ 07017 #if (cfgCheckMethodUse == cfgTrue) 07018 /* Check the capabilities of the current task */ 07019 privCheckCapabilities(callIdTaskFileAppendByte, ((cfgCapFileSystem) & 0xFF) ); 07020 /* Since appending works like a ring buffer, the byte will always fit. So we can 07021 * specify zero for both the offset and the size (whereas we usually have to specify 1. */ 07022 privCheckFileSpecsWriting(uiFileNumber,0,0,callIdTaskFileAppendByte); 07023 #endif 07024 #if (cfgCheckTrace == cfgTrue) || (cfgCheckMethodUse == cfgTrue) 07025 /* Here we can switch of that protection */ 07026 privExitSysCritical(); 07027 #endif 07028 /* We must know the size of the present file. */ 07029 Tuint08 uiFileSize = portFSReadByte((Taddress) (Tuint16) uiFileNumber); 07030 /* We must know the maximal space this file may occupy. */ 07031 Tuint08 uiFileSizeMax = privFileSpace(uiFileNumber); 07032 /* If the file is full, we wrap around */ 07033 if (uiFileSize >= uiFileSizeMax) 07034 { /* The next byte is written at the beginning. */ 07035 uiFileSize = 0; 07036 /* To protect the file from for example power down we first write the new length. This is not needed 07037 * if we don't wrap since in that case we do not overwrite any old information, so if the writing 07038 * is corrupted after writing the new byte, the old length is still an accurate value. */ 07039 portFSWriteByte((Taddress) (Tuint16) uiFileNumber,uiFileSize); 07040 /* Wait until we may write again */ 07041 privWaitForFsAccess(); } 07042 /* Get the location of the byte that must be written. */ 07043 Taddress pFileLoc = privFileLocation(uiFileNumber,uiFileSize); 07044 /* write the value, it is assumed any burnlocks are gone. */ 07045 portFSWriteByte(pFileLoc,bItem); 07046 /* Wait until we may write. */ 07047 privWaitForFsAccess(); 07048 /* Write the new length, thereby effectively creating the file. */ 07049 portFSWriteByte((Taddress) (Tuint16) uiFileNumber,uiFileSize+1); 07050 /* Wait until the write is over. The privWaitForFsAccess() blocks until 07051 * the burnlock has been cleared. */ 07052 privWaitForFsAccess(); } 07053 07054 #endif 07055 07056 07057 07058 #if (cfgUseFileSystem == cfgTrue) && (includeTaskFileReadPipe == cfgTrue) 07059 07060 void taskFileReadPipe(Tuint08 uiFileNumber, Tuint08 uiOffset, Tuint08 uiSize, void (*pipe)(Tchar)) 07061 { /* Call this if you want to read a byte stream from the file. Only call it inside fileOpen/fileClose 07062 * construct. Note that this method is interruptable by a tick interrupt.*/ 07063 #if (cfgCheckTrace == cfgTrue) 07064 /* We need protection for the maintenance functions. */ 07065 privEnterSysCritical(); 07066 /* Tell what we are doing */ 07067 privTraceAPI(callIdTaskFileReadPipe); 07068 /* Here we can switch of that protection */ 07069 privExitSysCritical(); 07070 #endif 07071 /* Get the location where to start. */ 07072 Taddress pFileLoc = privFileLocation(uiFileNumber,uiOffset); 07073 /* If we do not have a FAT length and size calculations are not possible. */ 07074 #if (cfgUseFileSystemMaintainFAT == cfgTrue) 07075 /* see if we must maximize the size */ 07076 if (uiSize == defUntilFileEnd) { uiSize = (Tuint08) portFSReadByte((Taddress) (Tuint16) uiFileNumber); } 07077 #endif 07078 /* Check if the user uses this method properly. We cannot do this at the start since the 07079 * parameters may have changed. We can postpone it because we have no writing here. Incorrect 07080 * reads are just wrapped. */ 07081 #if (cfgCheckMethodUse == cfgTrue) 07082 /* We need protection for the maintenance functions. */ 07083 privEnterSysCritical(); 07084 /* Check the capabilities of the current task */ 07085 privCheckCapabilities(callIdTaskFileReadPipe, ((cfgCapFileSystem) & 0xFF) ); 07086 /* Check if the parameters are such that operations stay within the filespace and are sensible. */ 07087 privCheckFileSpecsReading(uiFileNumber,uiOffset,uiSize,callIdTaskFileReadByte); 07088 /* Here we can switch of that protection */ 07089 privExitSysCritical(); 07090 #endif 07091 /* Loop through all bytes and read them */ 07092 while(uiSize--) 07093 { pipe((Tchar) portFSReadByte(pFileLoc)); 07094 /* After each read increase the pointer to get the next byte. */ 07095 pFileLoc++; } } 07096 07097 #endif 07098 07099 07100 #if (cfgUseFileSystem == cfgTrue) && (includeTaskFileReadBuffer == cfgTrue) 07101 07102 void taskFileReadBuffer(Tuint08 uiFileNumber, Tuint08 uiOffset, Tuint08 uiSize, Taddress pBuffer) 07103 { /* Call this if you want to read a byte stream from the file. You have managed access so 07104 * you cannot read beyond the end of the file. Only call it inside fileOpen/fileClose 07105 * construct. Note that this method is interruptible by a tick interrupt.*/ 07106 #if (cfgCheckTrace == cfgTrue) 07107 /* We need protection for the maintenance functions. */ 07108 privEnterSysCritical(); 07109 /* Tell what we are doing */ 07110 privTraceAPI(callIdTaskFileReadBuffer); 07111 /* Here we can switch of that protection */ 07112 privExitSysCritical(); 07113 #endif 07114 /* Get the location where to start. */ 07115 Taddress pFileLoc = privFileLocation(uiFileNumber,uiOffset); 07116 /* If we do not have a FAT length and size calculations are not possible. */ 07117 #if (cfgUseFileSystemMaintainFAT == cfgTrue) 07118 /* see if we must maximize the size */ 07119 if (uiSize == defUntilFileEnd) { uiSize = (Tuint08) portFSReadByte((Taddress) (Tuint16) uiFileNumber); } 07120 #endif 07121 /* Check if the user uses this method properly. We cannot do this at the start since the 07122 * parameters may have changed. We can posphone it because we have no writing here. Incorrect 07123 * reads are just wrapped. */ 07124 #if (cfgCheckMethodUse == cfgTrue) 07125 /* We need protection for the maintenance functions. */ 07126 privEnterSysCritical(); 07127 /* Check the capabilities of the current task */ 07128 privCheckCapabilities(callIdTaskFileReadBuffer, ((cfgCapFileSystem) & 0xFF) ); 07129 /* Check if the parameters are such that operations stay within the filespace and are sensible. */ 07130 privCheckFileSpecsReading(uiFileNumber,uiOffset,uiSize,callIdTaskFileReadBuffer); 07131 /* Here we can switch of that protection */ 07132 privExitSysCritical(); 07133 #endif 07134 /* Loop through all bytes and read them */ 07135 while(uiSize--) 07136 { *(pBuffer++) = portFSReadByte(pFileLoc); 07137 /* After each read increase the pointer to get the next byte. */ 07138 pFileLoc++; } } 07139 07140 #endif 07141 07142 07143 07144 #if (cfgUseFileSystem == cfgTrue) && (includeTaskFileWritePipe == cfgTrue) 07145 07146 void taskFileWritePipe(Tuint08 uiFileNumber, Tuint08 uiOffset, Tuint08 uiSize, Tchar (*pipe)(void)) 07147 { /* Call this if you want to write a byte stream from the file. You have managed access. You 07148 * can start at the beginning of a file or append at the end. Only call it inside fileOpen/fileClose 07149 * construct. Note that this method is interruptable by a tick interrupt.*/ 07150 #if (cfgCheckTrace == cfgTrue) 07151 /* We need protection for the maintenance functions. */ 07152 privEnterSysCritical(); 07153 /* Tell what we are doing */ 07154 privTraceAPI(callIdTaskFileWritePipe); 07155 /* Here we can switch of that protection */ 07156 privExitSysCritical(); 07157 #endif 07158 /* If we do not have a FAT length and size calculations are not possible. */ 07159 #if (cfgUseFileSystemMaintainFAT == cfgTrue) 07160 /* If we want to append to the file, we set the offset to point at the first new byte. */ 07161 if (uiOffset == defFromFileEnd) { uiOffset = (Tuint08) portFSReadByte((Taddress) (Tuint16) uiFileNumber); } 07162 /* Calculate the new size of the file. */ 07163 Tuint08 uiNewFileLength = uiOffset + uiSize; 07164 #endif 07165 /* Check if the user uses this method properly. We cannot do this at the start since the 07166 * parameters may have changed. But we must do it before any writing takes place. */ 07167 #if (cfgCheckMethodUse == cfgTrue) 07168 /* We need protection for the maintenance functions. */ 07169 privEnterSysCritical(); 07170 /* Check the capabilities of the current task */ 07171 privCheckCapabilities(callIdTaskFileWritePipe, ((cfgCapFileSystem) & 0xFF) ); 07172 /* Check if the parameters are such that operations stay within the filespace and are sensible. */ 07173 privCheckFileSpecsWriting(uiFileNumber,uiOffset,uiSize,callIdTaskFileWritePipe); 07174 /* Here we can switch of that protection */ 07175 privExitSysCritical(); 07176 #endif 07177 /* If we do not have a FAT length and size calculations are not possible. */ 07178 #if (cfgUseFileSystemMaintainFAT == cfgTrue) 07179 /* Clear the length of the file. Effectively the file is now gone. If the power goes down while 07180 * writing, the file will be deleted, but at least the file system will be in a consistent state. 07181 * This way we protect the file integrity. */ 07182 portFSWriteByte(((Taddress) (Tuint16) uiFileNumber),0); 07183 #endif 07184 /* Get the location where to start. */ 07185 Taddress pFileLoc = privFileLocation(uiFileNumber,uiOffset); 07186 /* Loop through all bytes and write them */ 07187 while(uiSize--) 07188 { /* Wait until we may write. We do not ask if the burnlock is present, for it most certainly 07189 * is, directly after a write operation. */ 07190 privWaitForFsAccess(); 07191 /* Get the bytes from the pipe and write them to the file system. */ 07192 portFSWriteByte(pFileLoc,pipe()); 07193 /* Adjust the pointer. (Do not issue this command like this: portFSWriteByte(pFileLoc++,pipe()), it will 07194 * generate a frame pointer and costs a lot of bytes. ) */ 07195 pFileLoc++; } 07196 /* If we do not have a FAT no size needs to be saved */ 07197 #if (cfgUseFileSystemMaintainFAT == cfgTrue) 07198 /* Wait until we may write. */ 07199 privWaitForFsAccess(); 07200 /* Write the new length, thereby effectively creating the file. */ 07201 portFSWriteByte((Taddress) (Tuint16) uiFileNumber,uiNewFileLength); 07202 #endif 07203 /* Wait until we may write */ 07204 privWaitForFsAccess(); } 07205 07206 #endif 07207 07208 07209 #if (cfgUseFileSystem == cfgTrue) && (includeTaskFileWriteBuffer == cfgTrue) 07210 07211 void taskFileWriteBuffer(Tuint08 uiFileNumber, Tuint08 uiOffset, Tuint08 uiSize, Taddress pBuffer) 07212 { /* Call this if you want to write a byte stream from the file. You have managed access. You 07213 * can start at the beginning of a file or append at the end. Only call it inside fileOpen/fileClose 07214 * construct. Note that this method is interruptible by a tick interrupt.*/ 07215 #if (cfgCheckTrace == cfgTrue) 07216 /* We need protection for the maintenance functions. */ 07217 privEnterSysCritical(); 07218 /* Tell what we are doing */ 07219 privTraceAPI(callIdTaskFileWriteBuffer); 07220 /* Here we can switch of that protection */ 07221 privExitSysCritical(); 07222 #endif 07223 /* If we do not have a FAT length and size calculations are not possible. */ 07224 #if (cfgUseFileSystemMaintainFAT == cfgTrue) 07225 /* If we want to append to the file, we set the offset to point at the first new byte. */ 07226 if (uiOffset == defFromFileEnd) { uiOffset = (Tuint08) portFSReadByte((Taddress) (Tuint16) uiFileNumber); } 07227 /* Calculate the new size of the file. */ 07228 Tuint08 uiNewFileLength = uiOffset + uiSize; 07229 #endif 07230 /* Check if the user uses this method properly. We cannot do this at the start since the 07231 * parameters may have changed. But we must do it before any writing takes place. */ 07232 #if (cfgCheckMethodUse == cfgTrue) 07233 /* We need protection for the maintenance functions. */ 07234 privEnterSysCritical(); 07235 /* Check the capabilities of the current task */ 07236 privCheckCapabilities(callIdTaskFileWriteBuffer, ((cfgCapFileSystem) & 0xFF) ); 07237 /* Check if the parameters are such that operations stay within the file space and are sensible. */ 07238 privCheckFileSpecsWriting(uiFileNumber,uiOffset,uiSize,callIdTaskFileWriteBuffer); 07239 /* Here we can switch of that protection */ 07240 privExitSysCritical(); 07241 #endif 07242 /* If we do not have a FAT length size modifications are not possible. */ 07243 #if (cfgUseFileSystemMaintainFAT == cfgTrue) 07244 /* Clear the length of the file. Effectively the file is now gone. If the power goes down while 07245 * writing, the file will be deleted, but at least the file system will be in a consistent state. 07246 * This way we protect the file integrity. */ 07247 portFSWriteByte(((Taddress) (Tuint16) uiFileNumber),0); 07248 #endif 07249 /* Get the location where to start. */ 07250 Taddress pFileLoc = privFileLocation(uiFileNumber,uiOffset); 07251 /* Loop through all bytes and write them */ 07252 while(uiSize--) 07253 { /* Wait until we may write. We do not ask if the burn lock is present, for it most certainly 07254 * is, directly after a write operation. */ 07255 privWaitForFsAccess(); 07256 /* Get the bytes from the pipe and write them to the file system. */ 07257 portFSWriteByte(pFileLoc,*pBuffer); 07258 /* Adjust the pointers. (Do not issue this command like this: portFSWriteByte(pFileLoc++,*(pBuffer++)), it will 07259 * generate a frame pointer and costs a lot of bytes. ) */ 07260 pBuffer++; 07261 pFileLoc++; } 07262 /* If we do not have a FAT no size needs to be saved */ 07263 #if (cfgUseFileSystemMaintainFAT == cfgTrue) 07264 /* Wait until we may write. */ 07265 privWaitForFsAccess(); 07266 /* Write the new length, thereby effectively creating the file. */ 07267 portFSWriteByte((Taddress) (Tuint16) uiFileNumber,uiNewFileLength); 07268 #endif 07269 /* Wait until we may write */ 07270 privWaitForFsAccess(); } 07271 07272 #endif 07273 07274 07275 #if (cfgUseEvents == cfgTrue) && (includeTaskWaitForEvents == cfgTrue) 07276 07277 #if (cfgUseTimeout == cfgTrue) 07278 void privWaitForEventBody(Tuint08 uiEventSet, Tuint16 uiTicksToWait) 07279 #else 07280 void privWaitForEventBody(Tuint08 uiEventSet) 07281 #endif 07282 { /* Call this if you want to wait for one or more events. 07283 * This is a switching call, let us first initialize the OS. 07284 * (It is a 'body' function too, see the explanation of this design elsewhere.) */ 07285 privInitOsSwitch(); 07286 /* Tell what we are doing. */ 07287 privTraceAPI(callIdTaskWaitForEvent); 07288 /* Check if the user uses this method properly. */ 07289 #if (cfgCheckMethodUse == cfgTrue) 07290 /* Check the capabilities of the current task */ 07291 privCheckCapabilities(callIdTaskWaitForEvent, ((cfgCapEvent) & 0xFF) ); 07292 #if (cfgUseTimeout == cfgTrue) 07293 /* Check the capabilities of the current task */ 07294 privCheckCapabilities(callIdTaskWaitForEvent, ((cfgCapTimeout) & 0xFF) ); 07295 /* Check if we do not violate the max delay time */ 07296 if (uiTicksToWait > defDelayTimeMax) 07297 /* Report an error and stop the task. */ 07298 { privShowError((errTaskDelayTooLong | errTaskStateCurrent | errOsStateAsIs), callIdTaskWaitForEvent, errCurrentTask ); } 07299 #endif 07300 #endif 07301 /* If we make use of timeouts, we write it as a delay. */ 07302 #if (cfgUseTimeout == cfgTrue) 07303 /* If we make use of timeouts, set the delay variable, which is used for the timeout. */ 07304 if (uiTicksToWait != defLockBlockInfinite) { privDelayCalcFromNow(uiTicksToWait); } 07305 #endif 07306 /* Get the task control block of the task that called this routine. */ 07307 TtaskControlBlock * curTCB = privTcbList(privTaskNumber(defCurrentTaskNumber)); 07308 /* Set the event block. This may contain one or more events. */ 07309 curTCB->uiTaskEvents = uiEventSet; 07310 /* block the task */ 07311 curTCB->uiTaskStatus = (curTCB->uiTaskStatus & (defBaseModeSetMask & defBaseBlockStateSetMask & defBaseDressSetMask)) | (defBaseModeSync | defBaseBlockStateBlocked | defBaseDressEvent); 07312 /* We are done, since we blocked we switch in any case. */ 07313 privEnterOS(defActionTaskStateSwitch); } 07314 07315 #endif 07316 07317 07318 #if (cfgUseEvents == cfgTrue) && (includeGenFireEvent == cfgTrue) && ((cfgUseEventsOnVariables == cfgTrue) || (defEventRegisterAtomicOperation == cfgFalse) || (cfgCheckTrace == cfgTrue)) 07319 07320 void genFireEvent(Tuint08 uiEvent) 07321 { /* Use this definition of getFireEvent if it is not possible to make use of privFireEvent directly. 07322 * This is the case if we need tracing, if the register is not located in a region reachable by 07323 * atomic bit setting or if you cannot supply a compile time constant to the routine. 07324 * We need global protection in any situation. */ 07325 privEnterGlobalCritical(); 07326 /* Tell what we are doing. */ 07327 privTrace(traceFireEvent | uiEvent); 07328 /* Check if the user uses this method properly. Note we do not need to activate capabilities for 07329 * the task using genFireEvent, so don't check for it. */ 07330 #if (cfgCheckMethodUse == cfgTrue) 07331 /* It makes a difference if the Femto OS needs one bit of the register for its own purpose. */ 07332 #if (cfgSysSqueezeState == cfgTrue) 07333 /* If not we only need to check if the Event number is a valid one. */ 07334 if ((uiEvent < defNumberEventBegin) || (uiEvent >= defNumberEventEnd)) 07335 #else 07336 /* Otherwise we must check is the same register is used for events and the AuxRegBit */ 07337 if (defEqualAuxiliaryRegisters) 07338 /* and if the event number coincides with this number*/ 07339 if ((uiEvent==devAuxSysRegBit) || (uiEvent < defNumberEventBegin) || (uiEvent >= defNumberEventEnd)) 07340 #endif 07341 /* If any of these conditions apply we signal an error. We cannot pas the uiEvent as info for 07342 * that can be a full 8 bit number. */ 07343 { privShowError((fatIllegalEvent | errTaskStateCurrent), callIdSystem, errCurrentTask); } 07344 #endif 07345 /* Fire the event now we know we may do so. */ 07346 privFireEvent(uiEvent); 07347 /* Remove the protection. */ 07348 privExitGlobalCritical(); } 07349 07350 #endif 07351 07352 07353 #if (cfgUseEvents == cfgTrue) && (includeGenCountEventBlocks == cfgTrue) 07354 07355 Tuint08 genCountEventBlocks(Tuint08 uiEventSet) 07356 { /* Call this if you want to know how many tasks are blocking on a particular combination of events. */ 07357 /* Don't allow for changes in the background. Handling events require global protection. 07358 * Please note that, even in that case, this may not be enough since the number may 07359 * be unreliable directly after is is returned. */ 07360 privEnterGlobalCritical(); 07361 /* Tell what we are doing. */ 07362 privTraceAPI(callIdGenCountEventBlocks); 07363 /* Check if the user uses this method properly. Note we do not need to activate capabilities 07364 * for the task using genCountEventBlocks, so don't check for it. */ 07365 #if (cfgCheckMethodUse == cfgTrue) 07366 /* It makes a difference if the Femto OS needs one bit of the register for its own purpose. */ 07367 #if (cfgSysSqueezeState == cfgFalse) 07368 /* We must check that no event is fired which is the same as the register used the AuxRegBit, thus 07369 * first check if the AuxRegBit and the event registers are shared */ 07370 if (defEqualAuxiliaryRegisters) 07371 /* and then check if this bit is not set. */ 07372 if ((uiEventSet & (1 << devAuxSysRegBit)) != 0) 07373 /* If any of these conditions apply we signal an error. */ 07374 { privShowError((fatIllegalEvent | errTaskStateCurrent) , callIdGenCountEventBlocks, errCurrentTask); } 07375 #endif 07376 #endif 07377 /* Reset the counter for blocked tasks. */ 07378 Tuint08 Result = 0; 07379 /* Loop through all tasks possibly waiting on an event. */ 07380 Tuint08 uiLoopTask; 07381 for (uiLoopTask=defTaskNumberEventBegin; uiLoopTask<defTaskNumberEventEnd; uiLoopTask++) 07382 { TtaskControlBlock * loopTCB = privTcbList(uiLoopTask); 07383 /* Test if the task is really waiting on all the events, and increase the counter if so. */ 07384 if ((loopTCB->uiTaskEvents & uiEventSet) == uiEventSet) { Result++; } } 07385 /* We are done */ 07386 privExitGlobalCritical(); 07387 /* Return the number of tasks that are waiting on this particular EventSet */ 07388 return Result; } 07389 07390 #endif 07391 07392 07393 #if (cfgUseEvents == cfgTrue) && (includeGenFireEventSet == cfgTrue) 07394 07395 void genFireEventSet(Tuint08 uiEventSet) 07396 { /* Call this if you want to release all tasks waiting for events. It has its 07397 * own interrupt protection. We must acquire global protection, for tick protection 07398 * may not be sufficient. */ 07399 privEnterGlobalCritical(); 07400 /* Tell what we are doing. */ 07401 privTraceAPI(callIdGenFireEventSet); 07402 /* Set all events. */ 07403 #if (cfgSysSqueezeState == cfgFalse) 07404 /* In case the Femto makes use of the auxiliary bit, we must check if the register for the 07405 * events does not collide with the registers that holds that bit. If so, that is not a valid 07406 * event flag. */ 07407 if (defEqualAuxiliaryRegisters) 07408 { /* The space for the events is shared with the auxiliary bit needed by the OS, make sure we do not 07409 * set that bit. */ 07410 portEventRegister = preBitClr1(uiEventSet,devAuxSysRegBit); } 07411 else 07412 #endif 07413 { portEventRegister = uiEventSet; } 07414 /* leave the protected zone, and we are done. */ 07415 privExitGlobalCritical(); } 07416 07417 #endif