#include <avr/io.h>
#include <avr/interrupt.h>
#include "os.h"
#include "kernel.h"
#include "error_code.h"
Go to the source code of this file.
Defines | |
#define | SAVE_CTX_TOP() |
#define | STACK_SREG_SET_I_BIT() |
#define | SAVE_CTX_BOTTOM() |
#define | SAVE_CTX() SAVE_CTX_TOP();SAVE_CTX_BOTTOM(); |
Push all the registers and SREG onto the stack. | |
#define | RESTORE_CTX() |
Pop all registers and the status register. | |
Functions | |
int | main () |
main function provided by user application. The first task to run. | |
static void | kernel_main_loop (void) |
The heart of the RTOS, the main loop where the kernel is entered and exited. | |
static void | kernel_dispatch (void) |
The second part of the scheduler. | |
static void | kernel_handle_request (void) |
The first part of the scheduler. | |
static void | exit_kernel (void) |
The idle task does nothing but busy loop. | |
static void | enter_kernel (void) |
All system calls eventually enter here. | |
void | TIMER1_COMPA_vect (void) |
The interrupt handler for output compare interrupts on Timer 1. | |
static int | kernel_create_task () |
Kernel function to create a new task. | |
static void | kernel_terminate_task (void) |
Kernel function to destroy the current task. | |
static void | kernel_event_wait (void) |
Kernel function to place current task in a waiting queue. | |
static void | kernel_event_signal (uint8_t is_broadcast, uint8_t and_next) |
Kernel function to signal waiting processes. | |
static void | enqueue (queue_t *queue_ptr, task_descriptor_t *task_to_add) |
Add a task the head of the queue. | |
static task_descriptor_t * | dequeue (queue_t *queue_ptr) |
Pops head of queue and returns it. | |
static void | kernel_update_ticker (void) |
Update the current time. | |
static void | check_PPP_names (void) |
Validate the PPP array. | |
void | OS_Init () |
Setup the RTOS and create main() as the first SYSTEM level task. | |
static void | _delay_25ms (void) |
Delay function adapted from <util/delay.h>. | |
void | OS_Abort (void) |
Abort the execution of this RTOS due to an unrecoverable erorr. | |
int | Task_Create (void(*f)(void), int arg, unsigned int level, unsigned int name) |
void | Task_Next () |
The calling task gives up its share of the processor voluntarily. | |
void | Task_Terminate () |
The calling task terminates itself. | |
int | Task_GetArg (void) |
Retrieve the assigned parameter. | |
EVENT * | Event_Init (void) |
Initialize a new, non-NULL Event descriptor. | |
void | Event_Wait (EVENT *e) |
Wait for the next occurrence of a signal on e. The calling process always blocks. | |
void | Event_Signal (EVENT *e) |
Resume a single waiting task on e. It is a no-op if there is no waiting process. | |
void | Event_Broadcast (EVENT *e) |
Resume ALL waiting tasks on e. It is a no-op if there is no waiting process. | |
void | Signal_And_Next (EVENT *e) |
Resume a waiting task on e and at the same time relinquish the processor. | |
void | Broadcast_And_Next (EVENT *e) |
Resume ALL waiting tasks on e and at the same time relinquish the processor. | |
Variables | |
const unsigned char | PPP [] |
const unsigned int | PT |
static task_descriptor_t * | cur_task = NULL |
static volatile uint16_t | kernel_sp |
static task_descriptor_t | task_desc [MAXPROCESS+1] |
static task_descriptor_t * | idle_task = &task_desc[MAXPROCESS] |
static volatile kernel_request_t | kernel_request |
static volatile create_args_t | kernel_request_create_args |
static volatile int | kernel_request_retval |
static volatile EVENT * | kernel_request_event_ptr |
static queue_t | dead_pool_queue |
static uint8_t | num_events_created = 0 |
static queue_t | rr_queue |
static queue_t | system_queue |
static queue_t | event_queue [MAXEVENT] |
static uint8_t | ticks_remaining = 0 |
static uint8_t | slot_task_finished = 0 |
static int | slot_name_index = 0 |
static task_descriptor_t * | name_to_task_ptr [MAXNAME+1] |
static uint8_t | name_in_PPP [MAXNAME+1] |
static uint8_t volatile | error_msg = ERR_RUN_1_USER_CALLED_OS_ABORT |
Our implementation of the operating system described by Mantis Cheng in os.h.
Definition in file os.c.
#define SAVE_CTX_TOP | ( | ) |
Value:
asm volatile (\ "push r31 \n\t"\ "in r31,__SREG__ \n\t"\ "cli \n\t"::);
Save r31 and SREG on stack, disable interrupts, then save the rest of the registers on the stack. In the locations this macro is used, the interrupts need to be disabled, or they already are disabled.
#define STACK_SREG_SET_I_BIT | ( | ) |
#define SAVE_CTX | ( | ) | SAVE_CTX_TOP();SAVE_CTX_BOTTOM(); |
#define RESTORE_CTX | ( | ) |
int main | ( | ) |
main function provided by user application. The first task to run.
static void kernel_main_loop | ( | void | ) | [static] |
The heart of the RTOS, the main loop where the kernel is entered and exited.
The complete function is:
Loop
static void kernel_dispatch | ( | void | ) | [static] |
static void kernel_handle_request | ( | void | ) | [static] |
static void exit_kernel | ( | void | ) | [static] |
The idle task does nothing but busy loop.
This function is called by the kernel. Upon entry, we are using the kernel stack, on top of which is the address of the instruction after the call to exit_kernel().
Assumption: Our kernel is executed with interrupts already disabled.
The "naked" attribute prevents the compiler from adding instructions to save and restore register values. It also prevents an automatic return instruction.
enter_kernel | ( | void | ) | [static] |
All system calls eventually enter here.
Assumption: We are still executing on cur_task's stack. The return address of the caller of enter_kernel() is on the top of the stack.
TIMER1_COMPA_vect | ( | void | ) |
The interrupt handler for output compare interrupts on Timer 1.
Used to enter the kernel when a tick expires.
Assumption: We are still executing on the cur_task stack. The return address inside the current task code is on the top of the stack.
The "naked" attribute prevents the compiler from adding instructions to save and restore register values. It also prevents an automatic return instruction.
static int kernel_create_task | ( | ) | [static] |
Kernel function to create a new task.
When creating a new task, it is important to initialize its stack just like it has called "enter_kernel()"; so that when we switch to it later, we can just restore its execution context on its stack.
static void kernel_terminate_task | ( | void | ) | [static] |
static void kernel_event_wait | ( | void | ) | [static] |
static void kernel_event_signal | ( | uint8_t | is_broadcast, | |
uint8_t | and_next | |||
) | [static] |
static void enqueue | ( | queue_t * | queue_ptr, | |
task_descriptor_t * | task_to_add | |||
) | [static] |
static task_descriptor_t* dequeue | ( | queue_t * | queue_ptr | ) | [static] |
static void kernel_update_ticker | ( | void | ) | [static] |
static void check_PPP_names | ( | void | ) | [static] |
void OS_Init | ( | void | ) |
static void _delay_25ms | ( | void | ) | [static] |
void OS_Abort | ( | void | ) |
Abort the execution of this RTOS due to an unrecoverable erorr.
Abort the execution of this RTOS due to an unrecoverable erorr.
int Task_Create | ( | void(*)(void) | f, | |
int | arg, | |||
unsigned int | level, | |||
unsigned int | name | |||
) |
f | a parameterless function to be created as a process instance | |
arg | an integer argument to be assigned to this process instanace | |
level | assigned scheduling level: SYSTEM, PERIODIC or RR | |
name | assigned PERIODIC process name |
void Task_Next | ( | void | ) |
void Task_Terminate | ( | void | ) |
int Task_GetArg | ( | void | ) |
EVENT* Event_Init | ( | void | ) |
void Event_Wait | ( | EVENT * | e | ) |
void Event_Signal | ( | EVENT * | e | ) |
Resume a single waiting task on e. It is a no-op if there is no waiting process.
e | an Event descriptor |
void Event_Broadcast | ( | EVENT * | e | ) |
Resume ALL waiting tasks on e. It is a no-op if there is no waiting process.
e | an Event descriptor |
void Signal_And_Next | ( | EVENT * | e | ) |
Resume a waiting task on e and at the same time relinquish the processor.
e | an Event descriptor |
void Broadcast_And_Next | ( | EVENT * | e | ) |
Resume ALL waiting tasks on e and at the same time relinquish the processor.
e | an Event descriptor |
const unsigned char PPP[] |
PPP and PT defined in user application.
const unsigned int PT |
PPP and PT defined in user application.
task_descriptor_t* cur_task = NULL [static] |
volatile uint16_t kernel_sp [static] |
task_descriptor_t task_desc[MAXPROCESS+1] [static] |
task_descriptor_t* idle_task = &task_desc[MAXPROCESS] [static] |
volatile kernel_request_t kernel_request [static] |
volatile create_args_t kernel_request_create_args [static] |
Arguments for Task_Create() request.
volatile int kernel_request_retval [static] |
Return value for Task_Create() request.
volatile EVENT* kernel_request_event_ptr [static] |
queue_t dead_pool_queue [static] |
uint8_t num_events_created = 0 [static] |
queue_t system_queue [static] |
queue_t event_queue[MAXEVENT] [static] |
uint8_t ticks_remaining = 0 [static] |
uint8_t slot_task_finished = 0 [static] |
int slot_name_index = 0 [static] |
task_descriptor_t* name_to_task_ptr[MAXNAME+1] [static] |
uint8_t name_in_PPP[MAXNAME+1] [static] |
uint8_t volatile error_msg = ERR_RUN_1_USER_CALLED_OS_ABORT [static] |
Error message used in OS_Abort()