Skip to content

Commit

Permalink
[SCHEDULER ARCH] Wrote unit tests for scheduler + tick interrupt impl…
Browse files Browse the repository at this point in the history
…ementation
  • Loading branch information
Akashem06 committed Jun 9, 2024
1 parent 5b15172 commit 25df744
Show file tree
Hide file tree
Showing 11 changed files with 198 additions and 58 deletions.
10 changes: 5 additions & 5 deletions inc/mutex.h
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
#ifndef MUTEX_H
#define MUTEX_H

#include "task.h"
#include <stdbool.h>
#include <stddef.h>

#include "queue.h"
#include "rtos_status.h"

#include <stddef.h>
#include <stdbool.h>
#include "task.h"

typedef struct {
bool locked;
uint8_t priority;
TaskControlBlock *owner;
TaskControlBlock* owner;
Queue waiting_tasks;
} Mutex;

Expand Down
5 changes: 3 additions & 2 deletions inc/queue.h
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
#ifndef QUEUE_H
#define QUEUE_H

#include "rtos_status.h"
#include <stdint.h>
#include <stdbool.h>
#include <stdint.h>

#include "rtos_status.h"

typedef struct {
uint8_t *buffer;
Expand Down
36 changes: 18 additions & 18 deletions inc/rtos_status.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,25 @@
#define RTOS_STATUS_H

typedef enum {
RTOS_OK = 0,
RTOS_UNKNOWN,
RTOS_INVALID_ARGS,
RTOS_RESOURCE_EXHAUSTED,
RTOS_UNREACHABLE,
RTOS_TIMEOUT,
RTOS_EMPTY,
RTOS_OUT_OF_RANGE,
RTOS_UNIMPLEMENTED,
RTOS_UNINITIALIZED,
RTOS_INTERNAL_ERROR,
RTOS_INCOMPLETE,
RTOS_NUM_STATUS_CODES,
RTOS_OK = 0,
RTOS_UNKNOWN,
RTOS_INVALID_ARGS,
RTOS_RESOURCE_EXHAUSTED,
RTOS_UNREACHABLE,
RTOS_TIMEOUT,
RTOS_EMPTY,
RTOS_OUT_OF_RANGE,
RTOS_UNIMPLEMENTED,
RTOS_UNINITIALIZED,
RTOS_INTERNAL_ERROR,
RTOS_INCOMPLETE,
RTOS_NUM_STATUS_CODES,
} RTOSStatus;

#define status_ok_or_return(code) \
({ \
__typeof__(code) status_expr = (code); \
if (status_expr) return status_expr; \
}) \
#define status_ok_or_return(code) \
({ \
__typeof__(code) status_expr = (code); \
if (status_expr) return status_expr; \
})

#endif
9 changes: 6 additions & 3 deletions inc/scheduler.h
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
#ifndef SCHEDULER_H
#define SCHEDULER_H

#include "task.h"
#include "rtos_status.h"
#include <string.h>

#include "rtos_status.h"
#include "task.h"

RTOSStatus init_scheduler();
RTOSStatus create_task(TaskFunction task_function, uint32_t period, uint32_t deadline, const char *name);
RTOSStatus start_scheduler();
RTOSStatus create_task(TaskFunction taskFunction, uint8_t priority, const char *name);
RTOSStatus tick_handler();
RTOSStatus update_task_deadlines();

#endif
5 changes: 3 additions & 2 deletions inc/task.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ typedef struct {
TaskFunction taskFunction; // Task function pointer
uint32_t *stackPointer; // Pointer to the task's stack
TaskState state; // Current state of the task
uint8_t priority; // Task priority
uint32_t delay; // Delay for task to unblock (for time-delayed tasks)
uint32_t period; // Task period/frequency
uint32_t deadline; // Deadline period storage variable
char taskName[16]; // Task name for debugging
} TaskControlBlock;

Expand All @@ -27,5 +27,6 @@ typedef struct {
extern TaskControlBlock task_list[MAX_TASKS];
extern uint32_t task_stacks[MAX_TASKS][STACK_SIZE];
extern uint8_t current_task_index;
extern uint32_t system_time;

#endif
17 changes: 4 additions & 13 deletions src/mutex.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ uint8_t mutex_buffer[MAX_TASKS];

RTOSStatus init_mutex(Mutex* mutex) {
mutex->locked = false;
mutex->priority = 0;
mutex->owner = NULL;
status_ok_or_return(init_queue(&mutex->waiting_tasks, mutex_buffer, MAX_TASKS));
return RTOS_OK;
Expand All @@ -14,27 +13,19 @@ RTOSStatus lock_mutex(Mutex* mutex) {
if (!mutex->locked) {
mutex->locked = true;
mutex->owner = &task_list[current_task_index];
mutex->priority = task_list[current_task_index].priority;
// Include HW Interrupt disable (TASK ENTER CRITICAL SECTION)
return RTOS_OK;
} else {
// Higher priority task requests the mutex
if (task_list[current_task_index].priority > mutex->priority) {
// Priority Inheritance
mutex->owner->priority = task_list[current_task_index].priority;
}
// Earlier deadline task requests the mutex

// Handle task requesting mutex

// Add the current index of the waiting task to the list
// Add the current index of the task to the waiting list and block it
enqueue(&mutex->waiting_tasks, current_task_index);
task_list[current_task_index].state = TASK_BLOCKED;


}

return RTOS_OK;
}

RTOSStatus unlock_mutex(Mutex* mutex) {
return RTOS_OK;
}
RTOSStatus unlock_mutex(Mutex* mutex) { return RTOS_OK; }
5 changes: 2 additions & 3 deletions src/queue.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,13 @@ RTOSStatus enqueue(Queue *queue, uint8_t data) {
return RTOS_OK;
}


RTOSStatus dequeue(Queue *queue, uint8_t *data) {
if (!queue->buffer) {
return RTOS_UNINITIALIZED;
}

data = &queue->buffer[queue->head];
queue->head = (queue->head + 1) %queue->len;
*data = queue->buffer[queue->head];
queue->head = (queue->head + 1) % queue->len;

return RTOS_OK;
}
85 changes: 76 additions & 9 deletions src/scheduler.c
Original file line number Diff line number Diff line change
@@ -1,24 +1,37 @@
#include "scheduler.h"

uint32_t earliest_deadline = UINT32_MAX;
TaskControlBlock task_list[MAX_TASKS];
uint32_t task_stacks[MAX_TASKS][STACK_SIZE];
uint8_t current_task_index;
uint32_t system_time;

RTOSStatus init_scheduler() {
current_task_index = 0;
earliest_deadline = UINT32_MAX;
system_time = 0;

for (int i = 0; i < MAX_TASKS; i++) {
task_list[i].state = TASK_SUSPENDED;
task_list[i].stackPointer = &task_stacks[i][STACK_SIZE - 1];
task_list[i].deadline = UINT32_MAX;
task_list[i].period = 0;
}

// Start tick counter

return RTOS_OK;
}

RTOSStatus create_task(TaskFunction task_function, uint8_t priority, const char *name) {
RTOSStatus create_task(TaskFunction task_function, uint32_t period, uint32_t deadline, const char *name) {
for (int i = 0; i < MAX_TASKS; i++) {
// If the task stack space is not being used yet
if (task_list[i].state == TASK_SUSPENDED) {
task_list[i].taskFunction = task_function;
task_list[i].priority = priority;
task_list[i].period = period;
task_list[i].deadline = deadline;
task_list[i].state = TASK_READY;

// Copies over name into taskName and states string end using \0
strncpy(task_list[i].taskName, name, sizeof(task_list[i].taskName));
task_list[i].taskName[sizeof(task_list[i].taskName) - 1] = '\0';
Expand All @@ -28,13 +41,13 @@ RTOSStatus create_task(TaskFunction task_function, uint8_t priority, const char

// ARM Cortex-M specific: Simulate the stack frame as if an interrupt had occurred
// Resource: https://interrupt.memfault.com/blog/cortex-m-rtos-context-switching#cortex-m-arm-mcu-features

// Initial xPSR value
*(task_list[i].stackPointer--) = 0x01000000; // Default xPSR value (Thumb state)
// Initial PC value
*(task_list[i].stackPointer--) = (uint32_t)task_function;
// Initial LR value
*(task_list[i].stackPointer--) = 0xFFFFFFFD; // Special value indicating task return
*(task_list[i].stackPointer--) = 0x01000000; // Default xPSR value (Thumb state)
// Initial PC value (Program Coutner register which holds next instruction to run)
*(task_list[i].stackPointer--) = (uintptr_t)task_function;
// Initial LR value (Return address)
*(task_list[i].stackPointer--) = 0xFFFFFFFD; // Special value indicating task return

// Initialize R12, R3, R2, R1, and R0 to zero
for (int j = 0; j < 5; j++) {
Expand All @@ -45,9 +58,63 @@ RTOSStatus create_task(TaskFunction task_function, uint8_t priority, const char
for (int j = 0; j < 8; j++) {
*(task_list[i].stackPointer--) = 0x00000000;
}


return RTOS_OK;
}
}
return RTOS_INTERNAL_ERROR;
}

RTOSStatus start_scheduler() {
for (int i = 0; i < MAX_TASKS; i++) {
if (task_list[i].state == TASK_READY && task_list[i].deadline < earliest_deadline) {
current_task_index = i;
earliest_deadline = task_list[i].deadline;
break;
}
}

if (earliest_deadline != UINT32_MAX) {
task_list[current_task_index].state = TASK_RUNNING;
// Directly call the task function for simulation
task_list[current_task_index].taskFunction();
}

return RTOS_OK;
}

// ISR for hardware timer ticks
RTOSStatus tick_handler() {
system_time = (system_time + 1) % UINT32_MAX;
uint8_t next_task_index = current_task_index;

for (int i = 0; i < MAX_TASKS; i++) {
if (task_list[i].state == TASK_READY && task_list[i].deadline < earliest_deadline) {
earliest_deadline = task_list[i].deadline;
next_task_index = i;
}
}

if (next_task_index != current_task_index) {
task_list[current_task_index].state = TASK_READY;
task_list[next_task_index].state = TASK_RUNNING;

current_task_index = next_task_index;

task_list[current_task_index].taskFunction();
}
return RTOS_OK;
}

RTOSStatus update_task_deadlines() {
for (int i = 0; i < MAX_TASKS; i++) {
if (task_list[i].state == TASK_READY || task_list[i].state == TASK_RUNNING) {
// Update the deadline if the task has a period set
if (task_list[i].period > 0) {
task_list[i].deadline = system_time + task_list[i].period;
}
}
}

return RTOS_OK;
}
4 changes: 2 additions & 2 deletions tests/dummy_test.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#include "CppUTest/TestHarness.h"

// create a test group
TEST_GROUP(dummy_test){
TEST_GROUP(DummyTest){

};

// create a test for that test group
TEST(dummy_test, pass_me) { CHECK_EQUAL(1, 1); }
TEST(DummyTest, PassMe) { CHECK_EQUAL(1, 1); }
3 changes: 2 additions & 1 deletion tests/main.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "CppUTest/CommandLineTestRunner.h"

IMPORT_TEST_GROUP(dummy_test);
IMPORT_TEST_GROUP(DummyTest);
IMPORT_TEST_GROUP(TestScheduler);

int main(int ac, char** av)
{
Expand Down
Loading

0 comments on commit 25df744

Please sign in to comment.