/* Scheduler Last updated 1.11.01 */ #include "H8.h" #include "Timers.h" #define DisableTimer DisableT0 #define EnableTimer EnableT0 #ifndef Scheduler_H_DEFINED #define Scheduler_H_DEFINED /* One of the processes is currently running. The rest of the processes are either ready to run or blocked waiting for an event. A process ready to run is either urgent or just ready. The urgent processes takes priority when the next process is scheduled for running. The processes blocked can wait for either a timeout, a boolean condition to become true or one of these events to happend. The timeouts and conditions are monitored by the scheduler on each activation. Each process is identified by an integer index. This is used as an index to access the process descriptor for each process. The currently running process has index Current. The main program has index 0. */ #define MaxProcesses 5 enum state_t { Urgent, Ready, WaitingTimeout, WaitingCondition, WaitingConditionOrTimeout }; typedef enum state_t state; struct ProcessDescriptor_t { word SavedSP; state State; word Timeout; byte * Cond; }; typedef struct ProcessDescriptor_t ProcessDescriptor; static volatile ProcessDescriptor ProcessTable [ MaxProcesses ]; static int Current; /* Index of current process */ static int LastProcess; /* Index of last entry used in process table */ /* Common stack area for all processes */ #define StackSize 250 #define StackAreaSize (MaxProcesses * StackSize) static word ProcessStack [ StackAreaSize ]; int16 StartProcess ( void (* p)(void) ) { int16 result, StackPointerIndex; DisableTimer; if ( LastProcess == (MaxProcesses - 1) ) result = -1; else { LastProcess = LastProcess + 1; result = LastProcess; StackPointerIndex = (LastProcess+1)*StackSize; /* Initial stack depends on the generated code for WDTHandler */ ProcessStack[ --StackPointerIndex] = (word) p; /* pc */ ProcessStack[ --StackPointerIndex] = 0; /* cc */ ProcessStack[ --StackPointerIndex] = 0; /* r6 */ ProcessStack[ --StackPointerIndex] = T0_DispatcherReturnAddress; ProcessStack[ --StackPointerIndex] = 0; /* r6 */ ProcessStack[ --StackPointerIndex] = 0; /* r4 */ ProcessStack[ --StackPointerIndex] = 0; /* r0 */ ProcessStack[ --StackPointerIndex] = 0; /* r1 */ ProcessStack[ --StackPointerIndex] = 0; /* r2 */ ProcessStack[ --StackPointerIndex] = 0; /* r3 */ ProcessStack[ --StackPointerIndex] = 0; /* r5 */ ProcessTable[ LastProcess ].SavedSP= (word) &(ProcessStack[StackPointerIndex]); ProcessTable[ LastProcess ].State = Ready; } EnableTimer; return result; } /* Wait until Cond is TRUE or Timeout. Returns FALSE at Timeout otherwise TRUE. Timeout is measured in ms from the time of call. */ byte WaitUntil( byte * Cond, word Timeout ) { byte result; DisableTimer; if ( ! ( *Cond || ( Timeout == 0 ) ) ) { /* Block process and wait for timeout or condition */ ProcessTable[ Current ].State = WaitingConditionOrTimeout; ProcessTable[ Current ].Timeout = Timeout; ProcessTable[ Current ].Cond = Cond; while ( ProcessTable[ Current ].State == WaitingConditionOrTimeout ){ EnableTimer; DisableTimer; } } result = * Cond; EnableTimer; return result; } #define WaitOrBreak(b,d) if (WaitUntil( & b, d )) break #define WaitOrReturn(b,d) if (WaitUntil( & b, d )) return FALSE /* Wait for a time interval measures in msec */ void PauseMS ( word Duration ) { DisableTimer; if ( ! ( Duration == 0 ) ) { /* Block process and wait for timeout */ ProcessTable[ Current ].State = WaitingTimeout; ProcessTable[ Current ].Timeout = Duration; while ( ProcessTable[ Current ].State == WaitingTimeout ){ EnableTimer; DisableTimer; } } EnableTimer; } /* Semaphore operations */ #define semaphore byte void Signal ( semaphore * s ) { DisableTimer; *s = TRUE; EnableTimer; } void Wait ( semaphore * s ) { DisableTimer; if ( !( *s ) ) { /* Block process and wait for condition */ ProcessTable[Current].State = WaitingCondition; ProcessTable[Current].Cond = s; while ( ProcessTable[Current].State == WaitingCondition ) { EnableTimer; DisableTimer; } } *s = FALSE; EnableTimer; } static int16 ProcessIndex; static int16 NewCurrent; static byte NotFound; static byte UrgentProcess; word ScheduleProcess( word SavedSP ) { /* Keep track of wake up conditions and timeouts */ UrgentProcess = FALSE; for ( ProcessIndex = 0; ProcessIndex <= LastProcess; ProcessIndex++){ switch ( ProcessTable[ ProcessIndex ].State ) { case Urgent: UrgentProcess = TRUE; break; case Ready: break; case WaitingTimeout: ProcessTable[ ProcessIndex ].Timeout --; if ( ProcessTable[ ProcessIndex ].Timeout == 0 ) { ProcessTable[ ProcessIndex ].State = Urgent; UrgentProcess = TRUE; } break; case WaitingCondition: if ( *ProcessTable[ ProcessIndex ].Cond ) { ProcessTable[ ProcessIndex ].State = Urgent; UrgentProcess = TRUE; } break; case WaitingConditionOrTimeout: ProcessTable[ ProcessIndex ].Timeout --; if ( *ProcessTable[ ProcessIndex ].Cond || ( ProcessTable[ ProcessIndex ].Timeout == 0 ) ) { ProcessTable[ ProcessIndex ].State = Urgent; UrgentProcess = TRUE; } break; } } if ( UrgentProcess ) { /* Find next urgent process */ ProcessIndex = Current; NotFound = TRUE; while ( NotFound ) { ProcessIndex++ ; if ( ProcessIndex > LastProcess ) ProcessIndex = 0; if ( ProcessTable[ ProcessIndex ].State == Urgent ){ ProcessTable[ ProcessIndex ].State = Ready; NewCurrent = ProcessIndex; NotFound = FALSE; } } } else { /* Find next ready process, there should alway be at least one ready process in the program. */ ProcessIndex = Current; NotFound = TRUE; while ( NotFound ) { ProcessIndex++ ; if ( ProcessIndex > LastProcess ) ProcessIndex = 0; if ( ProcessTable[ ProcessIndex ].State == Ready ){ NewCurrent = ProcessIndex; NotFound = FALSE; } } } ProcessTable[ Current ].SavedSP = SavedSP; Current = NewCurrent; return ( ProcessTable[ Current ].SavedSP ); } /* Should be called before timer interrupts are enabled */ void SchedulerInit ( void ) { Current = 0; LastProcess = 0; ProcessTable[ Current ].State = Ready; } void SchedulerClose( void ) { } #endif /* Scheduler_H_DEFINED */