Zu den für Anfänger am schnellsten zu verstehenden Echtzeitbetriebssystemen gehört µC/OS von Jean J. Labrosse ( siehe http://www.micrium.com ).
Es kann in den Versionen 1.xx bis zu 63 Applikationstasks mit je unterschiedlichen Prioritäten verwalten und gehört zu den Echtzeitbetriebssystemen mit dem geringsten Speicherbedarf.
pC/OS wurde basierend auf der Orginalversion µC/OS 1.00 aus dem Embedded Systems Programming Magazine(1992) weiterentwickelt.
Da in der Originalversion Daten durch direkte Übergabe von Zeigern zwischen den Tasks ausgetauscht werden, und somit keine Garantie für die freie Verwendbarkeit des Absender-buffers nach Übergabe an einen anderen Task besteht und, viel wichtiger, der Empfänger einen
Zeiger in das Datenfeld eines anderen Tasks erhält (Pointer-Fehler / Längen-Fehler / Manipulationen u.a.) wurden die Mechanismen für Message-Box und Queue entsprechend so geändert, daß nun die Daten über einen Kernel-internen Buffer an den
Empfänger übergeben werden. Das bedeutet, daß der Kernel zu übertragende Daten in einen eigenen Buffer kopiert und bei Übergabe an den Empfänger diese auch wieder selber in den durch den Empfänger bereitgestellten Buffer kopiert.
Das bringt zwar einen höheren Speicherbedarf je Queue mit sich, sichert aber dafür die Prozesse weitestgehend (für Real-Mode) voneinander ab.
Aus Sicherheitsgründen wurden außerdem Kernel-Konstanten in den CODE-Area verlegt.
Desweiteren wurde der Kernel um die Diente Pipe, Eventgroup, Mutex, Timerservice und dyn. Memorymanagement erweitert.
Um diese Änderungen eindeutig zu deklarieren wurde der Namen, angelehnt an dem immer größer werdenden Original "µC/OS", auf pC/OS wie "pico-C.." geändert.
Special zu: Priority Inversion, das Problem und die Lösungsansätze
bekannter Bug:
Wenn ein niederpriorisierter Task auf eine Recource wartet, und ein höherpriorisierter Task diese Recource setzt, so wird der schlafende Task in den Ready-state versetzt. Da der höherpriorisierte Task weiterläuft, darf dieser die selbe Recource nicht wieder auslesen, da ansonsten der niederpriorisierte Task bei Ausführung 'vorzeitig' mit dem Return-Code OS_TIMEOUT zurück kommt.
Bitte beachten Sie, daß einige Funktionen unter dem selben Namen wie im Original aber mit modifizierten Parametern bzw. Zeigern deklariert sind.
User-Functions:
Task-Control: | Description |
OS_Init | Initialisierung des Kernels |
OS_Start | Beginn der Kernelservices |
OS_TaskCreate | Anlegen eines Tasks |
OS_ChangePrio | Änderung der Priorität des aktiven Tasks |
OS_TaskChangePrio | Änderung der Priorität eines aktiven/ready Tasks |
OS_TaskDelete | Löschen eines aktiven/ready Tasks |
OS_TaskIdDelete | Löschen eines aktiven/ready Tasks via unique ID |
OS_TaskGetStatus | Gibt den aktuellen Status eines Tasks zurück |
OS_TaskIdGetStatus | Gibt den aktuellen Status eines Tasks via unique ID zurück |
OS_TaskGetID | Gibt die unique ID eines Tasks zurück |
OS_TaskGetPrio | Gibt die Priorität eines Tasks zurück |
OS_TaskIdDestroy | Löschen eines Tasks via unique ID, auch wenn dieser an einer IPC wartet oder eine Mutex inne hat & freigeben aller Memory Allokationen |
OS_TaskSuspend | Suspendiert einen Task |
OS_TaskIdSuspend | Suspendiert einen Task via unique ID |
OS_TaskResume | Wiederaufwecken eines suspendierten Tasks |
OS_TaskIdResume | Wiederaufwecken eines suspendierten Tasks via unique ID |
OS_TimeDly | Legt laufenden Task für bestimmte Zeit schlafen |
OS_TimeDlyResume | Wiederaufwecken eines schlafenden Tasks vor Ablauf der eingestellten Zeit |
OS_TimeDlyIdResume | Wiederaufwecken eines schlafenden Tasks via unique ID vor Ablauf der eingestellten Zeit |
OS_Lock | Unterdrücken des Shedulers (keine Taskwechsel) |
OS_Unlock | Wiederzuschaltung des Shedulers (Taskwechsel bei Ereignis oder Zeit) |
OS_GetRev | Gibt Zeiger auf Kernel-Revision zurück |
Dynamic-Memory: | Description |
OS_MemoryInit | Erzeugen des Speicherpools |
OS_MemAlloc | Allokieren von Speicher |
OS_MemFree | Freigeben von allokiertem Speicher |
Mailboxes: | Description |
OS_MboxInit | Anlegen einer Mailbox |
OS_MboxPost | Sendet Daten an höchstpriorisierten Empfänger dieser Mailbox |
OS_MboxPostAbbort | Bricht Warten eines sendenden Tasks (höchste wartende Prio) an einer Mailbox ab |
OS_MboxPend | Wartet auf Daten aus einer Mailbox |
OS_MboxPendAbbort | Bricht Warten eines empfangenden Tasks (höchste wartende Prio) an einer Mailbox ab |
Queues: | Description |
OS_QueueInit | Anlegen einer Queue |
OS_QueueInfo | Informationen über eine Queue einholen |
OS_QueuePost | Sendet Daten in eine Queue |
OS_QueueFrontPost | Sendet Daten an den Anfang einer Queue |
OS_QueuePostAbbort | Bricht Warten eines sendenden Tasks (höchste wartende Prio) an einer Queue ab |
OS_QueuePend | Wartet auf Daten aus einer Queue |
OS_QueuePendAbbort | Bricht Warten eines empfangenden Tasks (höchste wartende Prio) an einer Queue ab |
OS_QueueClear | Löscht alle Daten in einer Queue |
Pipes: | Description |
OS_PipeInit | Anlegen einer Pipe |
OS_PipeInfo | Informationen über eine Pipe einholen |
OS_PipePost | Sendet Daten in eine Pipe |
OS_PipeFrontPost | Sendet Daten an den Anfang einer Pipe |
OS_PipePostAbbort | Bricht Warten eines sendenden Tasks (höchste wartende Prio) an einer Pipe ab |
OS_PipePend | Wartet auf Daten aus einer Pipe |
OS_PipePendAbbort | Bricht Warten eines empfangenden Tasks (höchste wartende Prio) an einer Pipe ab |
OS_PipeClear | Löscht alle Daten in einer Pipe |
Semaphores: | Description |
OS_SemInit | Anlegen einer Semaphore |
OS_SemAccept | wartet auf Ereignis und gibt Anzahl zurück |
OS_SemPost | Freigabe einer belegten Semaphore / setzt Ereignis |
OS_SemPend | Belegt eine Semaphore / wartet auf Ereignis |
OS_SemPendAbbort | Bricht Warten eines Tasks (höchste wartende Prio) an einer Semaphore ab |
OS_SemClear | Löscht Semaphoren-Counter |
Mutexes: | Description |
OS_MutexCreate | Anlegen einer Mutex |
OS_MutexPost | gibt Mutex wieder frei |
OS_MutexPend | Besetzt die Mutex |
OS_MutexPendAbbort | Bricht Warten eines Tasks (höchste wartende Prio) an einer Mutex ab |
Event-Groups: | Description |
OS_EvgInit | Anlegen einer Eventgruppe |
OS_EvgPost | Setzt ein/mehrere Events einer Evengruppe |
OS_EvgPend | Wartet auf das Eintreffen eines oder mehrere Events einer Eventgruppe |
OS_EvgPendAbbort | Bricht Warten eines Tasks (höchste wartende Prio) an einer Eventgruppe ab |
Timer-Service: | |
OS_TimerCreate | Anlegen eines Timers |
OS_TimerDelete | Löschen eines angelegten Timers |
OS_TimerStart | (Re-)Starten eines angelegten Timers |
OS_TimerStop | Stoppen eines angelegten Timers |
OS_TimerGetState | gibt den Status eines angelegten Timers zurück |
OS_TimerGetRemain | gibt die verbleibende Zeit eines laufenden Timers zurück |
System-Ticks: | |
OS_TimeSet | Setzt Ticker auf übergebenen Wert |
OS_TimeGet | Gibt aktuellen Ticker-Wert zurück |
Interrupts: | Description |
OS_IntEnter | Registrierung einer aufgerufenen ISR |
OS_IntExit | Ende einer aufgerufenen ISR |
History: | Description |
OS_HistoryPost | Schreibt Eintrag in History |
OS_HistoryRead | Gibt ersten History-Eintrag und löscht diesen in der Tabelle |
Error-Codes:
|
Name |
Decimal_Value |
Description |
OS_SUCCESS / OS_NO_ERR | 0 | no errors |
OS_TIMEOUT | 10 | timeout condition occurs during waiting for a resource |
OS_MBOX_FULL | 20 | Mailbox fully (with OS_NO_SUSP) |
OS_MBOX_NODATA | 21 | no message in Mailbox (with OS_NO_SUSP) |
OS_Q_FULL | 30 | Queue fully (with OS_NO_SUSP) |
OS_Q_NODATA | 31 | no byte in Queue (with OS_NO_SUSP) |
OS_Q_CLEAR | 32 | Queue was cleared during waiting |
OS_PRIO_EXIST | 40 | under this priority, a other Task is registered |
OS_TASK_NOT_EXIST | 41 | under this priority, no Task is registered |
OS_SEM_ERR | 50 | internal error in Semaphore-handling |
OS_SEM_NODATA | 51 | Semaphore occupy / no event (with OS_NO_SUSP) |
OS_SEM_OVF | 52 | Error in the Semaphore-handling (Counter too big) |
OS_MUX_ERR | 55 | Error in Mutex-handling |
OS_MUX_NOACC | 56 | Mutex occupied (with OS_NO_SUSP) |
OS_MUX_USED | 57 | to change Task have a Mutex occupied |
OS_P_FULL | 60 | Pipe fully (with OS_NO_SUSP) |
OS_P_NODATA | 61 | no package in Pipe (with OS_NO_SUSP) |
OS_P_CLEAR | 62 | Pipe was cleared during waiting |
OS_P_LEN_ERR | 63 | Package too long |
OS_MEM_ERR | 70 | parameter error / internal error |
OS_MEM_OVF | 71 | memeory overflow |
OS_EVG_ERR | 80 | Error in Event-Group handling |
OS_EVG_NOE | 81 | Event(s) appeared not (with OS_NO_SUSP) |
OS_HIS_END | 90 | no (more) entry existing |
OS_SUSPEND_IDLE | 100 | the Idle-Task cannot be suspended |
OS_PRIO_INVALID | 101 | the value of priority is bigger OS_MIN_PRIO |
OS_TIME_NOT_DLY | 102 | the task doesn't sleep |
OS_TASK_SUSP_PRIO | 103 | under this priority, no Task is registered |
OS_TASK_NOT_SUSP | 104 | the task is not suspended |
OS_TASK_NOT_RDY | 105 | the task is not ready |
OS_TMR_NO_TIME | 106 | no time given on TimerCreate |
OS_TMR_NOT_EXIST | 107 | timer was not created / registered |
Der pC/OS Kernel stellt neben der zu verwendenden Hardware-Portierung mehrere Möglichkeiten zur Konfiguration von Services/IPCs sowie zur Reduzierung des Speicherbedarfs - Code-size bei Compilern die "unused code" nicht eindeutig identifizieren können und RAM - zur Verfügung.
Diese sind in der Datei "OS_cfg.h" zusammengefaßt.
components configuration | description |
OS_SYSTEM_TICKS_PER_SEC | system ticks per secound |
OS_TIMER_TICKS_PER_SEC | timer ticks per secound (see Timer-Service / TIMERS), can be tick faster than the kernel(system)-ticks |
OS_TASK_EXT_EN | include code for extended TASKS services |
OS_TASK_DESTROY_EN | include code for destroy pending/waiting TASKS, needs OS_TASK_EXT_EN too |
OS_SEM_EN | include code for SEMAPHORES |
OS_SEM_EXT_EN | include code for extended SEMAPHORES services |
OS_MUX_EN | include code for MUTEXES |
OS_MBOX_EN | include code for MAILBOXES |
OS_Q_EN | include code for QUEUES |
OS_P_EN | include code for PIPES |
OS_EVG_EN | include code for EVENTGROUPS |
OS_TMR_EN | include code for TIMERS |
OS_MEM_EN | include code for MEMORY-MANAGER |
OS_HIS_EN | include code for HISTORY |
OS_STK_CHECK_EN | check end-of-stack of old task during context switch |
OS_STK_CHECK_FILL | fill stack with 0xEF pattern to get the deep of use |
user configuration | description |
OS_MAX_TASKS | max created tasks in hole system --> max 64 ! |
OS_MIN_PRIO | lowest possible prio --> max 64 ! |
OS_IDLE_STK_SIZE | idle stack size in OS_STK_TYPE with fix (OS_MIN_PRIO - 1) as prio for idle task |
OS_TMR_PRIO | timer task prio, if OS_TMR_EN is not 0 |
OS_TMR_STK_SIZE | timer stack size in OS_STK_TYPE, if OS_TMR_EN is not 0 |
OS_MAX_HISTORY | history entries, if OS_HIS_EN is not 0 |
OS_STK_RESERVE | space between real end-of-stack and check-point in OS_STK_TYPE, if OS_STK_CHECK_EN is not 0 |
zu OS_MAX_TASKS und OS_MIN_PRIO:
Wenn ein System benötigt wird mit 5 Tasks wovon 2 Tasks eine gemeinsame Mutex benutzen, braucht man also OS_MAX_TASKS = 7 (incl. eine Mutex und Idle-Task) und OS_MIN_PRIO = 8 wobei der Idle-Task dann die Prio 7 erhält und alle anderen Tasks und die Mutex höhere Prioritäten bekommen (0..6). Soll auch der Timer-Service verwendet werden, so ist dieser Timer-Tasks zusätzlich einzubeziehen.
Initialisiert den Kernel und installiert den Idle-Task. Diese Funktion muß vor allen anderen Kerneldiensten bei der Systeminitialisierung einmal aufgerufen werden.
none
none
void main(void) { . . OS_Init(); . . OS_Start(); }
Startet den Kernel. Diese Funktion aktiviert das Multitasking und kehrt nicht zurück.
none
none
void main(void) { . . OS_Init(); . . OS_Start(); }
Legt einen neuen Task an. Diese Funktion initialisiert den Task-Control-Block und trägt den neuen Task mit seinem Stack und den Aufrufparametern ein. Dieses kann aus main() während der Initialisierung bzw. einem anderen Task in Laufzeit heraus erfolgen.
Wenn das optionale Feature "OS_STK_CHECK_EN" (Stack-End check) verwendet wird, benötigt der Kernel zusätzlich noch einen Pointer zum Stack-Ende.
*dptr
pointer to task-code
*data
pointer to parameter of this task
*pstk
pointer to stack of this task
*pstkend
pointer to end-of-stack of this task
prio
priority of this task
OS_NO_ERR
Task erfolgreich angelegt
OS_PRIO_EXIST
unter dieser Priorität existiert bereits ein Task
OS_PRIO_INVALID
diese Priorität ist für den Idle-Task reserviert bzw. der Wert der Priorität ist größer OS_MIN_PRIO
OS_STK_TYPE Task1Stack[STK_SIZE]; U08 Task1Data; void OS_FAR Task1(void *data); // forward declaration . . void main(void) { U08 state; . . OS_Init(); . state = OS_TaskCreate(Task1, (void *)&Task1Data, (void *)&Task1Stack[STK_SIZE], 18); . OS_Start(); } . . void OS_FAR Task1(void *data) { . . while(1) { . . . } }
Ändert die Priorität des aktuellen Tasks. Diese Funktion kann verwendet werden, um z.B. auf Grund eines Ereignisses (z.B. Events) die Priotität des Tasks zu verändern.
newp
new priority of this task
OS_NO_ERR
Priorität erfolgreich geändert
OS_PRIO_EXIST
unter dieser Priorität existiert bereits ein Task
OS_PRIO_INVALID
diese Priorität ist für den Idle-Task reserviert bzw. der Wert der Priorität ist größer OS_MIN_PRIO
OS_MUX_USED
der Task hat eine Mutex in Besitz
void OS_FAR Task1(void *data) { U08 state; . . while(1) { . state = OS_ChangePrio(38); . } }
Ändert die Priorität eines aktiven/ready Tasks. Diese Funktion kann verwendet werden, um z.B. auf Grund eines Ereignisses (z.B. Events) die Priotität eines aktiven/ready Tasks zu verändern.
Tasks die an einer Resource (Semaphore/Queue/Pipe/..) warten können nicht umpriorisiert werden, da dieser Zustand für den Kernel erkennbar ist aber nicht die exakte Resource selbst.
oldp
actual/old priority of the task
newp
new priority of the task
OS_NO_ERR
Priorität erfolgreich geändert
OS_PRIO_EXIST
unter dieser Priorität existiert bereits ein Task
OS_PRIO_INVALID
diese Priorität ist für den Idle-Task reserviert bzw. der Wert der Priorität ist größer OS_MIN_PRIO
OS_TASK_NOT_RDY
der Task ist nicht im RUNNING/READY-state und kann daher nicht umpriorisiert werden
OS_MUX_USED
der Task hat eine Mutex in Besitz
void OS_FAR Task1(void *data) { U08 state; . . while(1) { . state = OS_TaskChangePrio(38, 25); . } }
Entfernt den angegebenen Task. Diese Funktion kann verwendet werden, um z.B. auf Grund eines Ereignisses (Events) einen Task zu beenden/löschen. Dieser Task ist anschließend aus der Task-Control-Tabelle entfernt. Allokierte Resourcen des Tasks werden dabei NICHT automatisch freigegeben.
Um diesen Task später erneut ausführen zu können, muß er regulär mittels OS_TaskCreate neu angelegt werden.
Tasks die an einer Resource (Semaphore/Queue/Pipe/..) warten können so nicht beendet werden, da dieser Zustand für den Kernel erkennbar ist aber nicht die exakte Resource selbst.
prio
priority of the task to delete
OS_NO_ERR
Task gelöscht
OS_TASK_NOT_RDY
der Task ist nicht im RUNNING/READY-state und kann daher nicht gelöscht werden
OS_MUX_USED
der Task hat eine Mutex in Besitz
void OS_FAR Task1(void *data) { U08 state; . . while(1) { . state = OS_TaskDelete(OS_PRIO_SELF); . } }
Entfernt den angegebenen Task via unique-ID. Diese Funktion kann verwendet werden, um z.B. auf Grund eines Ereignisses (Events) einen Task zu beenden/löschen. Dieser Task ist anschließend aus der Task-Control-Tabelle entfernt. Allokierte Resourcen des Tasks werden dabei NICHT automatisch freigegeben.
Um diesen Task später erneut ausführen zu können, muß er regulär mittels OS_TaskCreate neu angelegt werden.
Tasks die an einer Resource (Semaphore/Queue/Pipe/..) warten können so nicht beendet werden, da dieser Zustand für den Kernel erkennbar ist aber nicht die exakte Resource selbst.
id
unique ID of the task to delete
OS_NO_ERR
Task gelöscht
OS_TASK_NOT_EXIST
unter dieser ID ist kein Task eingetragen
OS_TASK_NOT_RDY
der Task ist nicht im RUNNING/READY-state und kann daher nicht gelöscht werden
OS_MUX_USED
der Task hat eine Mutex in Besitz
void OS_FAR Task1(void *data) { U08 state; . . while(1) { . state = OS_TaskIdDelete(3); . } }
Gibt den aktuellen Status des angegebenen Tasks zurück.
prio
priority of the task
status
see "TASK STATUS", Bitmask
void OS_FAR Task1(void *data) { U08 status; . . while(1) { . status = OS_TaskGetStatus(6); . } }
Gibt den aktuellen Status des via unique-ID angegebenen Tasks zurück.
id
unique ID of the task
status
see "TASK STATUS", Bitmask
void OS_FAR Task1(void *data) { U08 status; . . while(1) { . status = OS_TaskIdGetStatus(2); . } }
Gibt die unique-ID das angegebenen Tasks zurück. Diese kann später verwendet werden, um z.B. einen Task - auch wenn er seine Prio inzwischen geändert hat oder gerade eine Mutex inne hat - gewaltsam zu beenden (see OS_TaskDestroy()).
prio
current priority of the task
ID
the unique-ID of this task
U08 idT1; void OS_FAR Task1(void *data) { . idT1 = OS_TaskGetID(OS_PRIO_SELF); . while(1) { . . } }
Gibt die aktuelle Priorität des via unique-ID angegebenen Tasks zurück.
id
unique ID of the task
PRIO
the priority of this task
U08 prioT1; void OS_FAR Task1(void *data) { . prioT1 = OS_TaskGetPrio(2); . while(1) { . . } }
Entfernt den angegebenen Task vollständig unabhängig von seinem Status. Diese Funktion kann verwendet werden, um z.B. auf Grund eines Ereignisses (Events) einen Task abzubrechen. Dieser Task ist anschließend aus der Task-Control-Tabelle, aus eventuell eingetragenen IPCs (Semaphore/MBox/Queue/Pipe/..) und dem Memory-Manager komplett entfernt.
Sollte der Tasks zu diesem Zeitpunkt eine Mutex besetzt haben, so wird diese freigegeben und eine User-CallBack Funktion aufgerufen, um eine eventuell notwendige Reinitialisierung der betroffenen Hardware o.ä. ausführen zu können (siehe OSMutexReInitResource() in "pC_OS_userCB.c"). Dies kann aber nur für eine Mutex (die letzte) erfolgen. Sollte der Task zwei Mutexes inne haben, so wird nur die zuletzt besetzte freigegeben !
Um diesen Task später erneut ausführen zu können, muß er regulär mittels OS_TaskCreate neu angelegt werden.
ACHTUNG:
Während dieser Task aus der der Task-Control-Tabelle und aus IPCs entfernt wird sind alle Interrupte unterbunden, da ein für diesen Task passendes Event zu einem Zugriff/Update Konflikt führen könnte. Während dem anschließenden Aufräumen im Memory-Manager sind Interrupte wieder zulässig aber ein Sheduling wird unterdrückt um ein gleichzeitiges Wiederhochfahren dieses Tasks mittels OS_TaskCreate() zu verhindern (prio of this task).
id
unique-ID of the task to destroy
OS_NO_ERR
Task vollständig entfernt
OS_TASK_NOT_EXIST
der angegebene Task existiert nicht
OS_TASK_NOT_RDY
der Task konnte nicht vollständig aus den IPCs oder einer Mutex entfernt werden
OS_MEM_ERR
beim Freigeben der Memory-Allokationen des Tasks ist ein Fehler aufgetreten
void OS_FAR Task1(void *data) { U08 state; . . while(1) { . state = OS_TaskIdDestroy(2); . } }
Suspendiert einen Task von der Ausführung durch den Kernel. Diese Funktion kann verwendet werden, um z.B. auf Grund eines Ereignisses (Events) einen Task vorrübergehend zu deaktivieren.
prio
priority of task to suspending
OS_NO_ERR
Task erfolgreich suspendiert
OS_SUSPEND_IDLE
der Idle-Task darf nicht suspendiert werden
OS_PRIO_INVALID
der Wert der Priorität ist größer OS_MIN_PRIO
OS_TASK_SUSP_PRIO
unter dieser Priorität ist kein Task eingetragen
OS_MUX_USED
der Task hat eine Mutex in Besitz
void OS_FAR Task1(void *data) { U08 state; . . while(1) { . state = OS_TaskSuspend(24); . } }
Suspendiert einen Task via seiner unique ID von der Ausführung durch den Kernel. Diese Funktion kann verwendet werden, um z.B. auf Grund eines Ereignisses (Events) einen Task vorrübergehend zu deaktivieren.
id
unique ID of task to suspending
OS_NO_ERR
Task erfolgreich suspendiert
OS_SUSPEND_IDLE
der Idle-Task darf nicht suspendiert werden
OS_TASK_SUSP_PRIO
unter dieser ID ist kein Task eingetragen
OS_MUX_USED
der Task hat eine Mutex in Besitz
void OS_FAR Task1(void *data) { U08 state; . . while(1) { . state = OS_TaskIdSuspend(4); . } }
Reaktiviert einen suspendierten Task. Diese Funktion kann verwendet werden, um z.B. auf Grund eines Ereignisses (z.B. Events) einen suspendierten Task wieder zu aktivieren.
prio
priority of suspended task
OS_NO_ERR
Task erfolgreich reaktiviert
OS_TASK_NOT_SUSP
der Task ist nicht suspendiert
OS_PRIO_INVALID
der Wert der Priorität ist größer OS_MIN_PRIO
OS_TASK_NOT_EXIST
unter dieser Priorität ist kein Task eingetragen
OS_MUX_USED
der Task hat eine Mutex in Besitz
void OS_FAR Task1(void *data) { U08 state; . . while(1) { . state = OS_TaskResume(24); . } }
Reaktiviert einen suspendierten Task basierend auf seiner unique ID. Diese Funktion kann verwendet werden, um z.B. auf Grund eines Ereignisses (z.B. Events) einen suspendierten Task wieder zu aktivieren.
id
unique ID of suspended task
OS_NO_ERR
Task erfolgreich reaktiviert
OS_TASK_NOT_SUSP
der Task ist nicht suspendiert
OS_TASK_NOT_EXIST
unter dieser ID ist kein Task eingetragen
OS_MUX_USED
der Task hat eine Mutex in Besitz
void OS_FAR Task1(void *data) { U08 state; . . while(1) { . state = OS_TaskIdResume(4); . } }
Legt den aktuellen Task für angegebene Kernel-Ticks schlafen. Diese Funktion kann verwendet werden, um z.B. auf Grund eines Ereignisses (Events) eine definierte Zeit verstreichen zu lassen. ACHTUNG! Mit dem Parameter OS_SUSPEND (0) wird der Task für immer deaktiviert und kann nie wieder aktiviert werden.
ticks
kernel-ticks as sleeping-time ( 1...65535 )
none
void OS_FAR Task1(void *data) { . . while(1) { . OS_TimeDly(200); . } }
Bricht die Wartezeit eines Tasks vorzeitig ab. Diese Funktion kann verwendet werden, um z.B. auf Grund eines Ereignisses (z.B. Events) einen schlafenden Task vorzeitig wieder zu aktivieren.
prio
priority of sleeping task
OS_NO_ERR
Task erfolgreich aufgeweckt
OS_TIME_NOT_DLY
der Task wartet nicht
OS_PRIO_INVALID
der Wert der Priorität ist größer OS_MIN_PRIO
OS_TASK_NOT_EXIST
unter dieser Priorität ist kein Task eingetragen
void OS_FAR Task1(void *data) { U08 state; . . while(1) { . state = OS_TimeDlyResume(24); . } }
Bricht die Wartezeit eines Tasks basierend auf seiner unique ID vorzeitig ab. Diese Funktion kann verwendet werden, um z.B. auf Grund eines Ereignisses (z.B. Events) einen schlafenden Task vorzeitig wieder zu aktivieren.
id
unique ID of sleeping task
OS_NO_ERR
Task erfolgreich aufgeweckt
OS_TIME_NOT_DLY
der Task wartet nicht
OS_TASK_NOT_EXIST
unter dieser ID ist kein Task eingetragen
void OS_FAR Task1(void *data) { U08 state; . . while(1) { . state = OS_TimeDlyIdResume(4); . } }
Schaltet den Sheduler aus. Diese Funktion kann verwendet werden, um z.B. atomare (nicht unterbrechbare) Vorgänge ausführen zu können, ohne daß ein Taskwechsel zwischendrin stattfinden kann.Die Interrupte werden weiterhin bedient.
none
none
void OS_FAR Task1(void *data) { . . while(1) { . OS_Lock(); . . // nicht unterbrechbarer Teil . OS_Unlock(); . } }
Schaltet den Sheduler wieder ein. Diese Funktion wird verwendet, um z.B. atomare (nicht unterbrechbare) Vorgänge abzuschliessen und einen Taskwechsel wieder zu ermöglichen
none
none
void OS_FAR Task1(void *data) { . . while(1) { . OS_Lock(); . . // nicht unterbrechbarer Teil . OS_Unlock(); . } }
Gibt einen Zeiger auf die Kernelrevision ( NULL-terminiertes ASCII-Array ) zurück.
none
*pointer
pointer to the address of array
void OS_FAR Task1(void *data) { U08 OS_FAR *Revision; . . while(1) { . Revision = OS_GetRev(); . } }
Initialisiert das dynamische Memory-Management. Diese Funktion muß für das dynamische Memory-Management bei der Systeminitialisierung einmal aufgerufen werden. Die Funktionen des dynamische Memory-Managements können auch ohne laufenden Kernel genutzt werden. ACHTUNG! Es wird keine Überprüfung des Speicherbereiches durchgeführt.
*mp
startaddress of memory-pool
size
size of memory-pool in bytes
OS_NO_ERR
Memory-Pool angelegt
OS_MEM_ERR
einer der Parameter ist NULL
Example for model-known memoryvoid main(void) { U08 state; . . // Memory: 512k - 64k(near) state = OS_MemoryInit((OS_MEM OS_HUGE *)(0x10000000), 458750); . . }
U08 memorypool[MEMSIZE]; void main(void) { U08 state; . state = OS_MemoryInit((OS_MEM OS_HUGE *)(memorypool), MEMSIZE); . . }
Allokieren eines benötigten Memorybereiches.
*MemPtr
pointer of pointer to get address of memory-area
size
size of needed memory in bytes
OS_NO_ERR
Speicher erfolgreich allokiert
OS_MEM_ERR
size ist NULL oder größer als Speicherbereich des Prozessors
OS_MEM_OVF
nicht genügend freier Speicher
void OS_FAR Task1(void *data) { U08 OS_HUGE *Addr_p; U08 state; . . while(1) { . state = OS_MemAlloc(&Addr_p, 3800); . } }
Freigeben eines allokierten Memorybereiches.
*MemPtr
pointer to address of memory-area
OS_NO_ERR
Speicher erfolgreich freigegeben
OS_MEM_ERR
Pointer ist NULL oder keine gültige Allokation vorgefunden
void OS_FAR Task1(void *data) { U08 OS_HUGE *Addr_p; U08 state; . . while(1) { . state = OS_MemAlloc(&Addr_p, 3800); . . state = OS_MemFree((OS_MEM OS_HUGE *)Addr_p); . } }
Initialisieren einer Mailbox. Mittels einer Mailbox können Daten jeglicher Art durch einen Zeiger übergeben werden. Dabei erhält der Empfänger jedoch einen Zeiger in das Datenfeld des Absenders!
*pmbox
pointer to Mailbox
OS_NO_ERR
Mailbox initialisiert
OS_MBOX MailBox1; void main(void) { U08 state; . . OS_Init(); . state = OS_MboxInit(&MailBox1); . }
Warten auf eine Nachricht aus einer Mailbox. Mit OS_NO_SUSP wird sofort zurückgekehrt auch wenn keine Nachrichten vorlagen und mit OS_SUSPEND wird solange gewartet bis eine Nachricht vorliegt (notfalls endlos).
*pmbox
pointer to Mailbox
*msg
pointer to receiving parameter (U32)
timeout
kernel-ticks as waiting-time ( 1...65534 )
OS_NO_ERR
Nachricht aus Mailbox erhalten
OS_MBOX_NODATA
keine Nachricht in Mailbox (bei OS_NO_SUSP)
OS_TIMEOUT
keine Nachricht in Mailbox (nach warten)
OS_MBOX MailBox1; void OS_FAR Task1(void *data) { U08 state; U32 Message; . . while(1) { . state = OS_MboxPend(&MailBox1, &Message, 200); . } }
Bricht das Warten eines empfangenden Tasks an der Mailbox ab.
Dabei wird nur der wartende Task mit der höchsten Priorität quasi "vorzeitig" ins TimeOut geschickt.
*pmbox
pointer to Mailbox
OS_NO_ERR
Warten eines Tasks abgebrochen
OS_TASK_NOT_EXIST
kein Task wartet an der Maibox
OS_MBOX MailBox1; void OS_FAR Task1(void *data) { U08 state; . . while(1) { . state = OS_MboxPendAbbort(&MailBox1); . } }
Sendet eine Nachricht in eine Mailbox. Mit OS_NO_SUSP wird sofort zurückgekehrt auch wenn die Mailbox voll war und mit OS_SUSPEND wird solange gewartet bis die Nachricht eingetragen werden kann (notfalls endlos).
*pmbox
pointer to Mailbox
*msg
pointer to message (U32)
timeout
kernel-ticks as waiting-time ( 1...65534 )
OS_NO_ERR
Nachricht in Mailbox gesendet
OS_MBOX_FULL
Mailbox voll (bei OS_NO_SUSP)
OS_TIMEOUT
Mailbox voll (nach warten)
OS_MBOX MailBox1; void OS_FAR Task1(void *data) { U08 state; U32 Message; . . while(1) { . Message =0x3076; state = OS_MboxPost(&MailBox1, &Message, OS_SUSPEND); . } }
Bricht das Warten eines sendenden Tasks an der Mailbox ab.
Dabei wird nur der wartende Task mit der höchsten Priorität quasi "vorzeitig" ins TimeOut geschickt.
*pmbox
pointer to Mailbox
OS_NO_ERR
Warten eines Tasks abgebrochen
OS_TASK_NOT_EXIST
kein Task wartet an der Maibox
OS_MBOX MailBox1; void OS_FAR Task1(void *data) { U08 state; . . while(1) { . state = OS_MboxPostAbbort(&MailBox1); . } }
Initialisieren einer Queue. Eine Queue dient der byte-weisen Übergabe von Daten an einen anderen Prozess nach dem FIFO-Prinzip. Innerhalb dieser Queue können <size> Bytes durch den Kernel-Puffer <*buffer> an andere Prozesse übergeben werden. Der Buffer kann durch direkte Deklaration ( U08 Buffer[size] ) oder durch dynamische Allokation erzeugt werden. Für die dynamische Allokation in Systemen mit segmentbasierter Speicherverwaltung ist die Typdeklaration OS_HUGE erforderlich, um über Segmentgrenzen hinweg ein Area ansprechen zu können.
*pq
pointer to Queue
*buffer
pointer to kernel-buffer
size
size of kernel-buffer in bytes
OS_NO_ERR
Queue initialisiert
OS_Q Queue1; U08 Q_Data1[256]; void main(void) { U08 state; . . OS_Init(); . state = OS_QueueInit(&Queue1, &Q_Data1[0], 256); . }
Abfrage des Status einer Queue. Durch diese Abfrage lassen sich diverse Parameter ihrer Initialisierung sowie ihr Füllstand ermitteln. Desweiteren kann die Priorität des wartenden Tasks ermittelt werden.
*pq
pointer to Queue
*size
pointer to variable will get the size
*used
pointer to variable will get the used-bytes at this time
*prio
pointer to variable will get the priority of waiting Task (if zero - no Task is waiting)
OS_NO_ERR
kein Fehler (für Erweiterungen)
OS_Q Queue1; void OS_FAR Task1(void *data) { U08 state; U16 size; U16 used; U08 prio; . . while(1) { . state = OS_QueueInfo(&Queue1, &size, &used, &prio); . } }
Warten auf ein Byte aus einer Queue. Mit OS_NO_SUSP wird sofort zurückgekehrt auch wenn keine Bytes vorlagen und mit OS_SUSPEND wird solange gewartet bis ein Byte vorliegt (notfalls endlos).
*pq
pointer to Queue
*msg
pointer to receiving Byte
timeout
kernel-ticks as waiting-time ( 1...65534 )
OS_NO_ERR
Byte aus Queue erhalten
OS_Q_NODATA
kein Byte in Queue (bei OS_NO_SUSP)
OS_TIMEOUT
kein Byte in Queue (nach warten)
OS_Q Queue1; void OS_FAR Task1(void *data) { U08 state; U08 Receive; . . while(1) { . state = OS_QueuePend(&Queue1, &Receive, 100); . } }
Bricht das Warten eines empfangenden Tasks an der Queue ab.
Dabei wird nur der wartende Task mit der höchsten Priorität quasi "vorzeitig" ins TimeOut geschickt.
*pq
pointer to Queue
OS_NO_ERR
Warten eines Tasks abgebrochen
OS_TASK_NOT_EXIST
kein Task wartet an der Queue
OS_Q Queue1; void OS_FAR Task1(void *data) { U08 state; . . while(1) { . state = OS_QueuePendAbbort(&Queue1); . } }
Sendet ein Byte in eine Queue. Mit OS_NO_SUSP wird sofort zurückgekehrt auch wenn die Queue voll war und mit OS_SUSPEND wird solange gewartet bis das Byte eingetragen werden kann (notfalls endlos).
*pq
pointer to Queue
msg
byte to send
timeout
kernel-ticks as waiting-time ( 1...65534 )
OS_NO_ERR
Byte in Queue gesendet
OS_Q_FULL
Queue voll (bei OS_NO_SUSP)
OS_TIMEOUT
Queue voll (nach warten)
OS_Q Queue1; void OS_FAR Task1(void *data) { U08 state; U08 Message; . . while(1) { . Message = 0x6A; state = OS_QueuePost(&Queue1, Message, 5000); . } }
Sendet ein Byte an den Anfang einer Queue. Somit wird dieses Byte durch den Empfänger zuerst wieder ausgelesen (vordrängeln). Mit OS_NO_SUSP wird sofort zurückgekehrt auch wenn die Queue voll war und mit OS_SUSPEND wird solange gewartet bis das Byte eingetragen werden kann (notfalls endlos).
*pq
pointer to Queue
msg
byte to send
timeout
kernel-ticks as waiting-time ( 1...65534 )
OS_NO_ERR
Byte in Queue gesendet
OS_Q_FULL
Queue voll (bei OS_NO_SUSP)
OS_TIMEOUT
Queue voll (nach warten)
OS_Q Queue1; void OS_FAR Task1(void *data) { U08 state; U08 Message; . . while(1) { . Message = 0x2D; state = OS_QueueFrontPost(&Queue1, Message, OS_NO_SUSP); . } }
Bricht das Warten eines sendenden Tasks an der Queue ab.
Dabei wird nur der wartende Task mit der höchsten Priorität quasi "vorzeitig" ins TimeOut geschickt.
*pq
pointer to Queue
OS_NO_ERR
Warten eines Tasks abgebrochen
OS_TASK_NOT_EXIST
kein Task wartet an der Queue
OS_Q Queue1; void OS_FAR Task1(void *data) { U08 state; . . while(1) { . state = OS_QueuePostAbbort(&Queue1); . } }
Löscht den Inhalt einer Queue und reaktiviert einen wartenden Sendeprozess. Diese Funktion kann für Fehlerbehandlungen verwendet werden, um den Datentransfer wieder neu zu starten. Die gelöschten Daten gehen dabei verloren.
*pq
pointer to Queue
OS_NO_ERR
Queue-Inhalt gelöscht
OS_Q Queue1; void OS_FAR Task1(void *data) { U08 state; . . while(1) { . . state = OS_QueueClear(&Queue1); . } }
Initialisieren einer Pipe. Eine Pipe dient der Paket-weisen Übergabe von Daten an einen anderen Prozess nach dem FIFO-Prinzip. Innerhalb dieser Pipe können maximal <deep> Pakete mit je maximal <size> Bytes eines Paketes durch den Kernel-Puffer <*buffer> an einen anderen Prozess übergeben werden. Der Buffer kann durch direkte Deklaration ( U08 Buffer[(size+2)*deep] ) oder durch dynamische Allokation erzeugt werden. Für die dynamische Allokation in Systemen mit segmentbasierter Speicherverwaltung ist die Typdeklaration OS_HUGE erforderlich, um über Segmentgrenzen hinweg ein Area ansprechen zu können. Die zusätzliche Länge von 2 Bytes pro Paket wird für die Speicherung der Paketlänge benötigt.
*pp
pointer to Pipe
*buffer
pointer to kernel-buffer
size
max size of data-bytes per paket
deep
max pakets in pipe
OS_NO_ERR
Pipe initialisiert
OS_P Pipe1; U08 P_Data1[(MAXPAKET+2)*8]; void main(void) { U08 state; . . OS_Init(); . state = OS_PipeInit(&Pipe1, P_Data1, MAXPAKET+2, 8); . }
Abfrage des Status einer Pipe. Durch diese Abfrage lassen sich diverse Parameter ihrer Initialisierung sowie ihr Füllstand ermitteln. Desweiteren kann die Priorität des wartenden Tasks ermittelt werden.
*pp
pointer to pipe
*size
pointer to variable will get the size per paket
*deep
pointer to variable will get the max pakets in pipe
*used
pointer to variable will get the used-pakets at this time
*prio
pointer to variable will get the priority of waiting Task (if zero - no Task is waiting)
OS_NO_ERR
kein Fehler (für Erweiterungen)
OS_P Pipe1; void OS_FAR Task1(void *data) { U08 state; U16 size; U08 deep; U08 used; U08 prio; . . while(1) { . state = OS_PipeInfo(&Pipe1, &size, &deep, &used, &prio); . } }
Warte auf ein Daten-Paket aus einer Pipe. Dabei muß der Empfänger-buffer ausreichend groß sein, um das Paket aufnehmen zu können. Da der Empfänger-buffer auch dynamisch allokiert sein kann, ist wiederum die Typdeklaration OS_HUGE erforderlich, um über Segmentgrenzen hinweg ein Area ansprechen zu können. Mit OS_NO_SUSP wird sofort zurückgekehrt auch wenn kein Paket vorlag und mit OS_SUSPEND wird solange gewartet bis ein Paket vorliegt (notfalls endlos).
*pp
pointer to pipe
*msg
pointer to receiving array
*lng
pointer to variable will get the lenght of paket
timeout
kernel-ticks as waiting-time ( 1...65534 )
OS_NO_ERR
Paket aus Pipe erhalten
OS_P_NODATA
kein Paket in Pipe (bei OS_NO_SUSP)
OS_TIMEOUT
kein Paket in Pipe (nach warten)
OS_P Pipe1; void OS_FAR Task1(void *data) { U08 state; U16 rLenght; U08 Receive[1024]; . . while(1) { . state = OS_PipePend(&Pipe1, Receive, &rLenght, OS_SUSPEND); . } }
Bricht das Warten eines empfangenden Tasks an der Pipe ab.
Dabei wird nur der wartende Task mit der höchsten Priorität quasi "vorzeitig" ins TimeOut geschickt.
*pp
pointer to Pipe
OS_NO_ERR
Warten eines Tasks abgebrochen
OS_TASK_NOT_EXIST
kein Task wartet an der Pipe
OS_P Pipe1; void OS_FAR Task1(void *data) { U08 state; . . while(1) { . state = OS_PipePendAbbort(&Pipe1); . } }
Sendet ein Paket in eine Pipe. Da der Sender-buffer auch dynamisch allokiert sein kann, ist wiederum die Typdeklaration OS_HUGE erforderlich, um über Segmentgrenzen hinweg ein Area ansprechen zu können. Mit OS_NO_SUSP wird sofort zurückgekehrt auch wenn die Pipe voll war und mit OS_SUSPEND wird solange gewartet bis das Paket eingetragen werden kann (notfalls endlos).
*pp
pointer to pipe
*msg
pointer to data-paket
lenght
lenght of data-paket
timeout
kernel-ticks as waiting-time ( 1...65534 )
OS_NO_ERR
Paket in Pipe gesendet
OS_P_FULL
Pipe voll (bei OS_NO_SUSP)
OS_P_LEN_ERR
Paket zu lang
OS_TIMEOUT
Pipe voll (nach warten)
OS_P Pipe1; void OS_FAR Task1(void *data) { U08 state; U08 Message[]={"Hallo Welt!"}; . . while(1) { . . state = OS_PipePost(&Pipe1, Message, strlen(Message), 500); . } }
Sendet ein Paket an den Anfang einer Pipe. Somit wird dieses Paket durch den Empfänger zuerst wieder ausgelesen (vordrängeln). Da der Sender-buffer auch dynamisch allokiert sein kann, ist wiederum die Typdeklaration OS_HUGE erforderlich, um über Segmentgrenzen hinweg ein Area ansprechen zu können. Mit OS_NO_SUSP wird sofort zurückgekehrt auch wenn die Pipe voll war und mit OS_SUSPEND wird solange gewartet bis das Paket eingetragen werden kann (notfalls endlos).
*pp
pointer to pipe
*msg
pointer to data-paket
lenght
lenght of data-paket
timeout
kernel-ticks as waiting-time ( 1...65534 )
OS_NO_ERR
Paket in Pipe gesendet
OS_P_FULL
Pipe voll (bei OS_NO_SUSP)
OS_P_LEN_ERR
Paket zu lang
OS_TIMEOUT
Pipe voll (nach warten)
OS_P Pipe1; void OS_FAR Task1(void *data) { U08 state; U08 Message[]={"Hallo Welt !"}; . . while(1) { . . state = OS_PipeFrontPost(&Pipe1, Message, strlen(Message), OS_NO_SUSP); . } }
Bricht das Warten eines sendenden Tasks an der Pipe ab.
Dabei wird nur der wartende Task mit der höchsten Priorität quasi "vorzeitig" ins TimeOut geschickt.
*pp
pointer to Pipe
OS_NO_ERR
Warten eines Tasks abgebrochen
OS_TASK_NOT_EXIST
kein Task wartet an der Pipe
OS_P Pipe1; void OS_FAR Task1(void *data) { U08 state; . . while(1) { . state = OS_PipePostAbbort(&Pipe1); . } }
Löscht den Inhalt einer Pipe und reaktiviert einen wartenden Sendeprozess. Diese Funktion kann für Fehlerbehandlungen verwendet werden, um den Datentransfer wieder neu zu starten. Die gelöschten Pakete gehen dabei verloren.
*pp
pointer to pipe
OS_NO_ERR
Pipe-Inhalt gelöscht
OS_P Pipe1; void OS_FAR Task1(void *data) { U08 state; . . while(1) { . . state = OS_PipeClear(&Pipe1); . } }
Initialisieren einer Semaphore. Eine Semaphore dient der Bedingungssynchonisation. Dazu gehören zwei Varianten der Nutzung einer Semaphore.
- binär: z.B. der Syncronisation von Zugriffen auf gemeinsame Recourcen/Variablen
- counting: Warten auf das Eintreten einer Bedingung(Signal) zur Steuerung der Reihenfolge von Prozessen.
Mit einer binären Semaphore kann z.B. eine State-Machine vor gleichzeitigen Zugriffen unterschiedlicher Prozesse (Read/Write) geschützt werden. So werden inkonsistente Zustände oder Daten vermieden. Jedoch kann in einigen Fällen Priority Inversion auftreten (siehe Sonder-Dokument), d.h. das ein niedriger Task die Recourcen besetzt hat, ein höherer Task deshalb warten muß und dann z.B. durch einen INT ein mittlerer Task(und seine Erben) die niedrigere Task für eine unbestimmte Zeit unterbricht. In einem solchen Fall wird die Semaphore mit 1 als cnt initialisiert, der Zugriff mittels OS_SemPend angefragt und mittels OS_SemPost wieder freigegeben.
Mit einer counting Semaphore wird das Eintreffen von Ereignissen signalisiert. So kann ein Prozess auf ein Signal warten um die Abarbeitungsreihenfolge einzuhalten. Mittels OS_SemAccept kann dabei auch die Zahl der inzwischen eingetretenen Ereignisse ermittelt werden. In einem solchen Fall wird die Semaphore mit 0 als cnt initialisiert, auf das Ereignis mittels OS_SemPend oder OS_SemAccept gewartet und mittels OS_SemPost das Ereignis gemeldet.
*psem
pointer to semaphore
cnt
start-count / max processes at the same time
OS_NO_ERR
Semaphore initialisiert
OS_SEM State1; void main(void) { U08 state; . . OS_Init(); . state = OS_SemInit(&State1, 1); . }
Reserviert eine Semaphore und somit den Zugriff auf die geschützte Recource bzw. wartet auf ein Ereignis. Mit OS_NO_SUSP wird sofort zurückgekehrt auch wenn die Semaphore nicht frei war bzw. kein Ereignis vorlag und mit OS_SUSPEND wird solange gewartet bis die Semaphore reserviert werden konnte bzw. das Ereignis eingetreten ist (notfalls endlos).
*psem
pointer to semaphore
timeout
kernel-ticks as waiting-time ( 1...65534 )
OS_NO_ERR
Semaphore reserviert / Ereignis lag vor
OS_SEM_NODATA
Semaphore besetzt / kein Ereignis (bei OS_NO_SUSP)
OS_TIMEOUT
Semaphore besetzt / kein Ereignis (nach warten)
OS_SEM State1; void OS_FAR Task1(void *data) { U08 state; . . while(1) { . state = OS_SemPend(&State1, OS_SUSPEND); . . } }
Bricht das Warten eines Tasks an der Semaphore ab.
Dabei wird nur der wartende Task mit der höchsten Priorität quasi "vorzeitig" ins TimeOut geschickt.
*psem
pointer to Semaphore
OS_NO_ERR
Warten eines Tasks abgebrochen
OS_TASK_NOT_EXIST
kein Task wartet an der Semaphore
OS_SEM State1; void OS_FAR Task1(void *data) { U08 state; . . while(1) { . state = OS_SemPendAbbort(&State1); . } }
Wird verwendet bei Nutzung der Semaphore als Event-Counter. Der Semaphoren-Counter wird dabei nicht beeinflußt. Ist der Counter größer 0 so wird der aktuelle Counterwert zurückgegeben. Mit OS_NO_SUSP wird sofort zurückgekehrt auch wenn der Semaphoren-Counter 0 ist und mit OS_SUSPEND wird solange gewartet bis das Ereignis einmal aufgetreten ist (notfalls endlos).
*psem
pointer to semaphore
*cnt
pointer to variable will get the counter-value
timeout
kernel-ticks as waiting-time ( 1...65534 )
OS_NO_ERR
Ereignis mind. 1 mal eingetreten
OS_SEM_NODATA
Counter gleich 0 (bei OS_NO_SUSP)
OS_TIMEOUT
Counter gleich 0 (nach warten)
OS_SEM Event1; void OS_FAR Task1(void *data) { U08 state; U16 EventCnt; . . while(1) { . state = OS_SemAccept(&Event1, &EventCnt, 500); . } }
Gibt eine reservierte Semaphore und somit den Zugriff auf die geschützte Recource wieder frei bzw. signalisiert ein Ereignis.
*psem
pointer to semaphore
OS_NO_ERR
Semaphore freigegeben / Ereignis gemeldet
OS_SEM_OVF
Fehler im Semaphoren-Handling (Counter zu groß)
OS_SEM State1; void OS_FAR Task1(void *data) { U08 state; . . while(1) { . . state = OS_SemPost(&State1); . } }
Löscht den Counter einer Semaphore. Diese Funktion kann zum Rücksetzten einer Counting-Semaphore oder für Fehlerbehandlungen verwendet werden, um das Semaphoren-Handling wieder neu zu starten. Bei Verwendung als binär Semaphore zur Steuerung von Zugriffen auf eine geschützte Recource muß im Anschluß bei Verwendung zum Fehlerhandling durch OS_SemPost die Semaphore sooft freigegeben werden, wie gleichzeitig Prozesse auf die Recource zugreifen dürfen.
*psem
pointer to semaphore
OS_NO_ERR
Semaphoren-cnt gelöscht
OS_SEM State1; void OS_FAR Task1(void *data) { U08 state; . . while(1) { . state = OS_SemClear(&State1); . } }
Anlegen bzw. Initialisieren einer Mutex (Mutual-Exclusion). Eine Mutex dient der Syncronisation von Zugriffen auf gemeinsame Recourcen/Variablen. Mit einer Mutex werden z.B. State-Machines vor gleichzeitigen Zugriffen unterschiedlicher Prozesse (Read/Write) geschützt. Der zweite Prozess muß warten, bis der erste Prozess seinen Zugriff (Read/Write) beendet hat. So werden inkonsistente Zustände oder Daten vermieden. Im Gegensatz zur Nutzung von Semaphoren kann dabei hier nicht der Effekt der Priority Inversion direkt auftreten (siehe Sonder-Dokument). Die Priorität der Mutex muß dabei höher sein, als die höchste Priorität der darauf zugreifenden Tasks. Die Mutex wird als nicht laufende Task eingetragen, sodaß unter der selben Priorität kein anderer Task laufen kann.
*pmux
pointer to mutex
prio
priority of this mutex
OS_NO_ERR
Mutex eingetragen und initialisiert
OS_MUX Mutex1; void main(void) { U08 state; . . OS_Init(); . state = OS_MutexCreate(&Mutex1, 10); . }
Reserviert eine Mutex und somit den Zufriff auf die geschützte Recource. Mit OS_NO_SUSP wird sofort zurückgekehrt auch wenn die Mutex nicht frei war und mit OS_SUSPEND wird solange gewartet bis die Mutex reserviert werden konnte (notfalls endlos).
*pmux
pointer to mutex
timeout
kernel-ticks as waiting-time ( 1...65534 )
OS_NO_ERR
Mutex reserviert
OS_MUX_NOACC
Mutex besetzt (bei OS_NO_SUSP)
OS_TIMEOUT
Mutex besetzt (nach warten)
OS_MUX_ERR
Fehler im Mutex-Handling
OS_MUX Mutex1; void OS_FAR Task1(void *data) { U08 state; . . while(1) { . state = OS_MutexPend(&Mutex1, OS_SUSPEND); . . } }
Bricht das Warten eines Tasks an der Mutex ab.
Dabei wird nur der wartende Task mit der höchsten Priorität quasi "vorzeitig" ins TimeOut geschickt.
*pmux
pointer to Mutex
OS_NO_ERR
Warten eines Tasks abgebrochen
OS_TASK_NOT_EXIST
kein Task wartet an der Mutex
OS_MUX Mutex1; void OS_FAR Task1(void *data) { U08 state; . . while(1) { . state = OS_MutexPendAbbort(&Mutex1); . } }
Gibt eine reservierte Mutex und somit den Zufriff auf die geschützte Recource wieder frei.
*pmux
pointer to mutex
OS_NO_ERR
Mutex freigegeben
OS_MUX_ERR
Fehler im Mutex-Handling
OS_MUX Mutex1; void OS_FAR Task1(void *data) { U08 state; . . while(1) { . . state = OS_MutexPost(&Mutex1); . } }
Initialisieren einer Event-Gruppe. Eine Eventgruppe besteht aus 32 Einzelevents, die in einem U32 zusammengefaßt einzeln als auch gruppiert verarbeitet werden können. Jedes Event innerhalb der Gruppe kann das Auftreten eines Ereignisses melden, jedoch keine Aussage darüber treffen, wie oft das Ereignis in der Zwischenzeit aufgetreten ist. Um Ereignisse auch zählen zu können, muß eine Semaphore als Counting-Semaphore für jedes einzelne Ereignis verwendet werden.(Semaphore mit 0 initialisieren , bei Auftreten des Ereignisses "OS_SemPost" und beim Warten "OS_SemAccept")
*pevg
pointer to eventgroup
OS_NO_ERR
Event-Gruppe initialisiert
OS_EVG Events1; void main(void) { U08 state; . . OS_Init(); . state = OS_EvgInit(&Events1); . }
Meldet das Auftreten eines bzw. mehrerer Events einer Event-Gruppe. Die Bit-Maske wird dabei als AND-Verknüpfung der Events interpretiert. D.h. alle Events, die in der Bit-Maske gesetzt sind, werden gemeldet. Mode dient der Nutzung dieser Funktion zum Löschen von Events.
*pevg
pointer to eventgroup
events
bit-mask of events
mode
mode of usement "OS_OR / OS_AND"
OS_NO_ERR
Event(s) gemeldet
OS_EVG Events1; void OS_FAR Task1(void *data) { U08 state; . . while(1) { . state = OS_EvgPost(&Events1,~0x00100000, OS_AND); // clear this event state = OS_EvgPost(&Events1, 0x00000100, OS_OR); // set this event . } }
Warten auf ein bzw. mehrere Events einer Event-Gruppe. Die Bit-Maske wird dabei zusammen mit dem Modi als Verknüpfung der Events interpretiert. D.h. bei OS_OR reicht bereits ein Event, das in der Bit-Maske gesetzt ist, für die Funktion und bei OS_AND müssen alle Events, die in der Bit-Maske gesetzt sind, eingetroffen sein. Mit OS_NO_SUSP wird sofort zurückgekehrt auch wenn kein Event aufgetreten ist und mit OS_SUSPEND wird solange gewartet bis das/ein/die Event(s) aufgetreten ist(sind) (notfalls endlos).
*pevg
pointer to eventgroup
events
bit-mask of events
mode
mode of usement "OS_OR / OS_AND"
timeout
kernel-ticks as waiting-time ( 1...65534 )
OS_NO_ERR
Event(s) aufgetreten
OS_EVG_NOE
Event(s) nicht aufgetreten (bei OS_NO_SUSP)
OS_TIMEOUT
Event(s) nicht aufgetreten (nach warten)
OS_EVG Events1; void OS_FAR Task1(void *data) { U08 state; . . while(1) { . state = OS_EvgPend(&Events1, 0x00100100, OS_OR, OS_SUSPEND); . } }
Bricht Warten eines Tasks (höchste wartende Prio) an einer Eventgruppe ab.
Dabei wird nur der wartende Task mit der höchsten Priorität quasi "vorzeitig" ins TimeOut geschickt.
*pevg
pointer to eventgroup
OS_NO_ERR
Warten eines Tasks abgebrochen
OS_TASK_NOT_EXIST
kein Task wartet an der Eventgruppe
OS_EVG Events1; void OS_FAR Task1(void *data) { U08 state; . . while(1) { . state = OS_EvgPendAbbort(&Events1); . } }
Anlegen bzw. Initialisieren eines Timers.
Ein Timer kann z.B. zu nachfolgenden Zwecken verwendet werden:
- timeouts innerhalb von Protokollschichten und Applikationen wie TCP/IP, X25, HTTP, FTP, ...
- verhindern des "verhungern" von Tasks durch Definition eines timeouts und entsprechenden Maßnahmen wie Prioritätsanhebung oder Anderes
- Steuerung periodischer Dienste oder Services
- soft-deadline / Watchdog von Diensten oder Services
Als mode können nachfolgende Angaben gemacht werden:
- OS_TMR_ENABLE - startet den Timer sofort
- OS_TMR_RONCE - Timer ist von Typ "run-once", d.h. nach einmaligem timeout wird er automatisch deaktiviert, bleibt aber eingetragen
- OS_TMR_CYCL - Timer ist vom Typ "cyclic / periodic", d.h. der Timer wird nach jedem timeout automatisch neu gestartet
- OS_TMR_CLR - Timer ist vom Typ "run-once auto-erase", d.h. wie run-once nur wird dieser Timer automatisch gelöscht und muß für einen weiteren Einsatz neu angelegt werden
Dabei gilt die Regelung OS_TMR_CLR geht vor OS_TMR_CYCL und dies vor OS_TMR_RONCE.
Die eingetragene CallBack-Funktion sollte möglichst kurz sein. Zur Informationsweitergabe kann ein Argument verwendet werden.
*ptmr
pointer to timer
time
timeout of this timer (in timer-ticks)
tFct
address of timeout-callback function
tArg
argument of timeout-callback function
mode
mode of this timer (run-once / cyclic / auto-clear)
OS_NO_ERR
Timer eingetragen und initialisiert
OS_TMR_NO_TIME
keine gültige Zeit als Parameter (time == 0)
OS_TMR Timer1; void TCP_To_CB(void *session) { OS_QueuePost(&TCPIP_To_Q, (U08)session, OS_NO_SUSP); } U08 TCP_send(void) { U08 state; U08 session; . . state = OS_TimerCreate(&Timer1, 30, TCP_To_CB, &session, OS_TMR_ENABLE | OS_TMR_CLR); . }
Deaktiviert und löscht einen Timer.
*ptmr
pointer to timer
OS_NO_ERR
timer gelöscht
OS_TMR_NOT_EXIST
der Timer war nicht eingetragen
OS_TMR Timer1; void OS_FAR Task1(void *data) { U08 state; . . while(1) { . state = OS_TimerDelete(&Timer1); . . } }
Startet einen deaktivierten, restarted einen run-once oder restartet einen laufenden Timer.
*ptmp
pointer to timer
time
new timeout (if not zero) of this timer (in timer-ticks)
OS_NO_ERR
Timer (re-)started
OS_TMR_NOT_EXIST
der Timer ist nicht eingetragen
OS_TMR Timer1; void OS_FAR Task1(void *data) { U08 state; . . while(1) { . state = OS_TimerStart(&Timer1, 0); . . } }
Stoppt / deaktiviert einen laufenden Timer.
*ptmr
pointer to timer
OS_NO_ERR
Timer gestoppt
OS_TMR_NOT_EXIST
der Timer ist nicht eingetragen
OS_TMR Timer1; void OS_FAR Task1(void *data) { U08 state; . . while(1) { . . state = OS_TimerStop(&Timer1); . } }
Gibt den Status eines angelegten Timers zurück.
Dabei werden folgende Informationen bereitgestellt:
- OS_TMR_ENABLE - der Timer läft aktuell
- OS_TMR_RONCE - Timer ist von Typ "run-once", d.h. nach einmaligem timeout wird er automatisch deaktiviert, bleibt aber eingetragen
- OS_TMR_CYCL - Timer ist vom Typ "cyclic / periodic", d.h. der Timer wird nach jedem timeout automatisch neu gestartet
- OS_TMR_CLR - Timer ist vom Typ "run-once auto-erase", d.h. wie run-once nur wird dieser Timer automatisch gelöscht und muß für einen weiteren Einsatz neu angelegt werden
Wenn der zurückgegebene Status nicht OS_TMR_ENABLE ist und OS_TMR_CLR, so wurde dieser Timer nie angelegt oder war "run-once auto-erase" und die Zeit war abgelaufen.
*ptmr
pointer to timer
status
Status des Timers (siehe "modi" bei OS_TimerCreate)
OS_TMR Timer1; void OS_FAR Task1(void *data) { U08 state; . . while(1) { . . state = OS_TimerGetState(&Timer1); if(state & OS_TMR_ENABLE) { . . } . } }
Gibt die verbleibende Zeit (in Timer-Ticks) eines laufenden Timers zurück.
Ist die Zeit gleich 0, so war der Timer abgelaufen oder wurde nie per OS_TimerCreate angelegt.
*ptmr
pointer to timer
time
verbleibende Zeit in Timer-Ticks
OS_TMR Timer1; void OS_FAR Task1(void *data) { U32 rtime; . . while(1) { . . rtime = OS_TimerGetRemain(&Timer1); . } }
Setzt den Kernel-internen Tick-Counter auf übergebenen Wert.
ticks
new value of tick-counter
none
void OS_FAR Task1(void *data) { . . while(1) { . OS_TimeSet(24837); . } }
Gibt den aktuellen Kernel-internen Tick-Counter-Wert zurück.
none
ticks
actual value of tick-counter
void OS_FAR Task1(void *data) { U32 time; . . while(1) { . time = OS_TimeGet(); . } }
Registriert eine Interrupt-Level. Dadurch werden keine Taskwechsel generiert. Diese Funktion ist für C-Code ISRs notwendig auf Prozessoren, bei denen Interrupte durch andere Interrupte unterbrochen werden können.
none
none
void OS_FAR ISR1(void) { OS_IntEnter(); . . . OS_IntExit(); }
Unregistriert eine Interrupt-Level. Dadurch werden Taskwechsel wieder generiert. Diese Funktion ist für C-Code ISRs notwendig auf Prozessoren, bei denen Interrupte durch andere Interrupte unterbrochen werden können.
none
none
void OS_FAR ISR1(void) { OS_IntEnter(); . . . OS_IntExit(); }
Trägt einen Eintrag in die History-Tabelle des Kernels ein. Zusätzlich zu den beiden Parametern werden noch die Priorität des Tasks und der Tick-Counter (als Zeitstempel) eingetragen.
param1
first 32-bit parameter for table
param2
secound 32-bit parameter for table
OS_NO_ERR
Eintrag geschrieben
OS_Q Queue5; void OS_FAR Task2(void *data) { U08 state; U08 Message; . . while(1) { . Message = 0x2D; state = OS_QueueFrontPost(&Queue5, Message, 200); if(state != OS_NO_ERR) OS_HistoryPost((U32)state, 0x0205); . } }
Liest nächsten Eintrag aus der History-Tabelle des Kernels und löscht diesen dabei.
*param1
pointer to variable will get the first 32-bit parameter
*param2
pointer to variable will get the secound 32-bit parameter
*prio
pointer to variable will get priority of task who has this written
*time
pointer to variable will get time-stamp of this entry
OS_NO_ERR
Eintrag gelesen
OS_HIS_END
kein Eintrag vorhanden
void OS_FAR Task3(void *data) { U08 state; U32 Hpara1; U32 Hpara2; U08 Tprio; U32 stamp; . . while(1) { . state = OS_HistoryRead(&Hpara1, &Hpara2, &Tprio, &stamp); . } }