femtoos_source/femtoos_core.c

Go to the documentation of this file.
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

Generated on Fri Oct 16 00:05:21 2009 for FemtoOS by  doxygen 1.5.2