Browse Source

OS up and running. Not perfect yet, though.

master
Maximilian Stiefel 7 years ago
parent
commit
89817d71ed
  1. 92
      software/os/error.c
  2. 49
      software/os/error.h
  3. 60
      software/os/heap.c
  4. 57
      software/os/heap.h
  5. 9
      software/os/helpers.c
  6. 13
      software/os/helpers.h
  7. 134
      software/os/mainyyy.c
  8. 47
      software/os/ossettings.h
  9. 49
      software/os/ostypes.h
  10. 44
      software/os/printf.c
  11. 23
      software/os/printf.h
  12. 16
      software/os/queues.h
  13. 197
      software/os/scheduler.c
  14. 45
      software/os/scheduler.h
  15. 22
      software/os/settings.h
  16. 38
      software/platform/system_timer.c
  17. 5
      software/platform/system_timer.h

92
software/os/error.c

@ -2,37 +2,14 @@
#include<string.h>
#include<stdint.h>
#include"error.h"
#include"settings.h"
#include"helpers.h"
#include"printf.h"
#include"ossettings.h"
uint8_t osItoa(int iint, char* iochar, size_t ibuffsize)
{
int i = 0;
int j = 0;
char z[10];
size_t buff_size_1 = ibuffsize;
size_t buff_size_2 = sizeof(z);
while(iint > 0)
{
z[i] = (char)('0' + iint % 10);
iint /= 10;
i++;
if( ((buff_size_1 - 1) < i) || ((buff_size_2 - 1) < i))
return 0;
}
j = i-1;
while(j >= 0)
{
iochar[j] = z[i-j-1];
j--;
}
iochar[i] = '\0';
return 1;
}
uint8_t osExplainError(const char* ifile, const int iline, const osError_t ierror, char* iomessage)
uint8_t osExplainError(const char* ifile, const uint8_t iline, const osError_t ierror, char* iomessage)
{
char z[10];
if(!osItoa(iline, z, sizeof(z)))
if( !osItoa(iline, z, sizeof(z), NULL) )
return 0;
strcat(iomessage, ifile);
strcat(iomessage, ":");
@ -42,22 +19,65 @@ uint8_t osExplainError(const char* ifile, const int iline, const osError_t ierro
{
case E_MAX_NUMBER_OF_TASKS:
strcat(iomessage, "Maximum number of tasks (N = ");
if(!osItoa(MAX_NUMBER_OF_TASKS, z, sizeof(z)))
return 0;
strcat(iomessage, z);
strcat(iomessage, ") is reached.\n");
if( !osItoa(MAX_NUMBER_OF_TASKS, z, sizeof(z), NULL) )
return 0;
strcat(iomessage, z);
strcat(iomessage, ") is reached.\n");
break;
case E_NULL_FORBIDDEN:
strcat(iomessage, "A NULL pointer is forbidden in this place.\n");
break;
case E_HEAP_OVERLFOW:
strcat(iomessage, "Maximum heap size (N = ");
if( !osItoa(HEAP_SIZE, z, sizeof(z), NULL) )
return 0;
strcat(iomessage, z);
strcat(iomessage, ") is reached.\n");
break;
default:
strcat(iomessage, "Unknown error or no explanation implemented yet.\n");
}
return 1;
}
uint8_t osPrintError(const char* ifile, const int iline, const osError_t ierror)
{
char iomessage[MAX_MESSAGE_SIZE] = {'\0'};
osExplainError(ifile, iline, ierror, iomessage);
#ifdef X86_TEST_ENVIRONMENT
return printf("%s", iomessage);
#else
return osPrintf("%s", iomessage);
#endif
}
uint8_t osExplainWarning(const char* ifile, const uint8_t iline, const osWarning_t ierror, char* iomessage)
{
char z[10];
if( !osItoa(iline, z, sizeof(z), NULL) )
return 0;
strcat(iomessage, ifile);
strcat(iomessage, ":");
strcat(iomessage, z);
strcat(iomessage, ": warning: ");
switch(ierror)
{
case W_SYS_TIMER_OVERFLOW:
strcat(iomessage, "System timer variable just had an overflow.");
break;
default:
strcat(iomessage, "Unknown error.\n");
strcat(iomessage, "Unknown warning or no explanation implemented yet.\n");
}
return 1;
}
void osPrintError(const char* ifile, const int iline, const osError_t ierror)
uint8_t osPrintWarning(const char* ifile, const int iline, const osWarning_t ierror)
{
char iomessage[MAX_MESSAGE_SIZE] = {'\0'};
osExplainError(ifile, iline, ierror, iomessage);
osExplainError(ifile, iline, ierror, iomessage);
#ifdef X86_TEST_ENVIRONMENT
printf("%s", iomessage);
return printf("%s", iomessage);
#else
return osPrintf("%s", iomessage);
#endif
}

49
software/os/error.h

@ -2,16 +2,59 @@
#define OS_ERROR_H
//--------------Includes-----------------
#include<ostypes.h>
#include"ostypes.h"
//--------------Preprocessor Hacks-------
/** Throws an error given an error type.
*
*/
#define THROW_ERROR(ERROR_TYPE)\
osPrintError(__FILE__, __LINE__, ERROR_TYPE)
/** Throws a warning given a warning type.
*
*/
#define THROW_WARNING(WARNING_TYPE)\
osPrintWarning(__FILE__, __LINE__, WARNING_TYPE)
//--------------Funtions-----------------
uint8_t osExplainError(const char* ifile, const int iline, const osError_t ierror, char* message);
void osPrintError(const char* ifile, const int iline, const osError_t ierror);
/** Creating a error message string from inter alia an error code.
*
* @param ifile Filename where error occurs.
* @param iline Line where error occurs.
* @param ierror Error code.
* @param message Message related to the error.
* @retval 1 (SUCCESS) or 0 (FAILURE).
*/
uint8_t osExplainError(const char* ifile, const uint8_t iline, const osError_t ierror, char* iomessage);
/** Print error. This is where the error output can be redirected (later).
*
* @param ifile Filename where error occurs.
* @param iline Line where error occurs.
* @param ierror Error code.
* @retval 1 (SUCCESS) or 0 (FAILURE).
*/
uint8_t osPrintError(const char* ifile, const int iline, const osError_t ierror);
/** Creating a warning message string from inter alia a warning code.
*
* @param ifile Filename where warning occurs.
* @param iline Line where warning occurs.
* @param ierror Warning code.
* @param message Message related to the warning.
* @retval 1 (SUCCESS) or 0 (FAILURE).
*/
uint8_t osExplainWarning(const char* ifile, const uint8_t iline, const osWarning_t ierror, char* iomessage);
/** Print warning. This is where the warning output can be redirected (later).
*
* @param ifile Filename where warning occurs.
* @param iline Line where warning occurs.
* @param ierror Warning code.
* @retval 1 (SUCCESS) or 0 (FAILURE).
*/
uint8_t osPrintWarning(const char* ifile, const int iline, const osWarning_t ierror);
#endif

60
software/os/heap.c

@ -5,24 +5,45 @@
#include"heap.h"
#include"error.h"
#include"ostypes.h"
#include"printf.h"
//--------------Functions----------------
/** Gives the index of the left child of a node.
*
* @param iind Index of the node itself.
* @retval Index of the left child of the node.
*/
static inline uint8_t osHeapChildL(uint8_t iind)
{
return (2*iind + 1);
}
/** Gives the index of the right child of a node.
*
* @param iind Index of the node itself.
* @retval Index of the left child of the node.
*/
static inline uint8_t osHeapChildR(uint8_t iind)
{
return (2*iind + 2);
}
/** Gives the index of the parent of a node.
*
* @param iind Index of the node itself.
* @retval Index of the left child of the node.
*/
static inline uint8_t osHeapParent(uint8_t iind)
{
return (iind-1)/2;
}
/** Gives the size of the heap.
*
* @param ioarray Array where the heap is stored.
* @retval Size of the heap.
*/
static inline uint8_t osHeapSize(osHeapNode_t* ioarray)
{
int i;
@ -34,19 +55,22 @@ static inline uint8_t osHeapSize(osHeapNode_t* ioarray)
return i;
}
/** Delete one element in the heap.
*
* @param ioarray Array where the heap is stored.
* @retval Index of the left child of the node.
*/
static inline void osHeapDelete(osHeapNode_t* ioarray, uint8_t ii)
{
ioarray[ii] = NULL;
}
void osHeapInit(osHeapNode_t* ioarray)
{
for(int i=0; i<HEAP_SIZE; i++)
{
osHeapDelete(ioarray, i);
}
}
/** Swap two elements in the heap.
*
* @param ioarray Array where the heap is stored.
* @param ia Index where element a is stored.
* @param ib Index where element b is stored.
*/
static inline void osHeapSwap(osHeapNode_t* ioarray, uint8_t ia, uint8_t ib)
{
osHeapNode_t z;
@ -55,6 +79,14 @@ static inline void osHeapSwap(osHeapNode_t* ioarray, uint8_t ia, uint8_t ib)
ioarray[ib] = z;
}
void osHeapInit(osHeapNode_t* ioarray)
{
for(int i=0; i<HEAP_SIZE; i++)
{
osHeapDelete(ioarray, i);
}
}
void osHeapHeapify(osHeapNode_t* ioarray, uint8_t iind)
{
uint8_t left = osHeapChildL(iind);
@ -149,9 +181,17 @@ void osHeapPrintS(osHeapNode_t* ioarray)
{
if(ioarray[i] == 0)
continue;
printf("%d ", ioarray[i]->priority);
#ifdef X86_TEST_ENVIRONMENT
printf("%d ", ioarray[i]->priority);
#else
osPrintf("%d ", ioarray[i]->priority);
#endif
}
printf("\n");
#ifdef X86_TEST_ENVIRONMENT
printf("\n");
#else
osPrintf("\n\r");
#endif
}
uint8_t osHeapIsEmpty(osHeapNode_t* ioarray)

57
software/os/heap.h

@ -1,5 +1,5 @@
#ifndef H_HEAP
#define H_HEAP
#ifndef OS_H_HEAP_
#define OS_H_HEAP_
//--------------Includes-----------------
@ -7,32 +7,59 @@
//--------------Functions----------------
static inline uint8_t osHeapChildL(uint8_t iind);
static inline uint8_t osHeapChildR(uint8_t iind);
static inline uint8_t osHeapParent(uint8_t iind);
static inline uint8_t osHeapSize(osHeapNode_t* ioarray);
static inline void osHeapDelete(osHeapNode_t* ioarray, uint8_t ii);
/** Initializes all heap elements by setting them to NULL.
*
* @param Array where the heap is stored.
*/
void osHeapInit(osHeapNode_t* ioarray);
static inline void osHeapSwap(osHeapNode_t* ioarray, uint8_t ia, uint8_t ib);
/** Classic heapify operation.
*
* @param ioarray Array where the heap is stored.
* @param iind Element to be put in the right place.
*/
void osHeapHeapify(osHeapNode_t* ioarray, uint8_t iind);
/** Build the heap from the bottom up. Given an array which is not heapified at all.
*
* @param ioarray Array where the heap is stored.
*/
void osHeapBuild(osHeapNode_t* ioarray);
/** Copy heap maximum.
*
* @param ioarray Array where the heap is stored.
* @param iomax Node, which is the maximum.
* @retval 1 (SUCCESS) or 0 (heap is empty).
*/
uint8_t osHeapMaximum(osHeapNode_t* ioarray, osHeapNode_t* iomax);
/** Copy heap maximum and remove it (extract).
*
* @param ioarray Array where the heap is stored.
* @param iomax Node, which is the maximum.
* @retval 1 (SUCCESS) or 0 (heap is empty).
*/
uint8_t osHeapExtractMaximum(osHeapNode_t* ioarray, osHeapNode_t* iomax);
/** Insert a node into the heap.
*
* @param ioarray Array where the heap is stored.
* @param x Node to be inserted into the heap.
* @retval 1 (SUCCESS) or 0 (heap is full).
*/
uint8_t osHeapInsert(osHeapNode_t* ioarray, osHeapNode_t x);
/** Print heap all priorities for debugging purposes.
*
* @param ioarray Array where the heap is stored.
*/
void osHeapPrintS(osHeapNode_t* ioarray);
/** Is the heap empty?
*
* @param ioarray Array where the heap is stored.
*/
uint8_t osHeapIsEmpty(osHeapNode_t* ioarray);
#endif
#endif /* OS_H_HEAP_ */

9
software/os/helpers.c

@ -24,6 +24,12 @@ uint8_t osItoa(int iint, char* iochar, size_t ibuffsize, size_t* obuffsize)
iint *= -1;
isnegative = 1;
}
if(iint == 0)
{
z[i] = '0';
i++;
}
/* Take last digit and convert until iint is gone. */
while(iint > 0)
{
@ -50,6 +56,7 @@ uint8_t osItoa(int iint, char* iochar, size_t ibuffsize, size_t* obuffsize)
iochar[j] = z[i-j-1];
j--;
}
*obuffsize = i;
if(obuffsize != NULL)
*obuffsize = i;
return 1;
}

13
software/os/helpers.h

@ -11,6 +11,12 @@
#include "stm32f10x.h"
#include <stdlib.h>
/** Simple inline power calculation.
*
* @param ibase Input base.
* @param iexponent Input exponent.
* @retval Result.
*/
inline int osPowInt(int ibase, int iexponent)
{
int result =1;
@ -21,6 +27,13 @@ inline int osPowInt(int ibase, int iexponent)
return result;
}
/** Simple Interger to ASCII conversion.
*
* @param iint Input integer.
* @param iochar C string where the result ends up.
* @param ibuffsize Size of the C string for security reasons.
* @param obuffsize Size of the string created by the function.
*/
uint8_t osItoa(int iint, char* iochar, size_t ibuffsize, size_t* obuffsize);
#endif /* OS_HELPERS_H_ */

134
software/os/mainyyy.c

@ -1,134 +0,0 @@
#define _GNU_SOURCE
#include<stdlib.h>
#include<stdio.h>
#include<assert.h>
#include<pthread.h>
#include<signal.h>
#include<sys/time.h>
#include<string.h>
#include<sched.h>
#include<unistd.h>
#include<errno.h>
#include"heap.h"
#include"ostypes.h"
#include"settings.h"
#include"scheduler.h"
#include"error.h"
// core_id = 0, 1, ... n-1, where n is the system's number of cores
int stick_this_thread_to_core(int core_id) {
int num_cores = sysconf(_SC_NPROCESSORS_ONLN);
if (core_id < 0 || core_id >= num_cores)
return EINVAL;
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(core_id, &cpuset);
pthread_t current_thread = pthread_self();
return pthread_setaffinity_np(current_thread, sizeof(cpu_set_t), &cpuset);
}
void myTask1(void *params)
{
char *str = (char*)params;
volatile int i;
static int counter = 0;
printf("%s. Executed task %d times.\n", str, ++counter);
for (i = 0; i < 100000; ++i);
osTaskDelay(10);
}
void myTask2(void *params)
{
char *str = (char*)params;
volatile int i;
static int counter = 0;
printf("%s. Executed task %d times.\n", str, ++counter);
for (i = 0; i < 100000; ++i);
osTaskDelay(20);
}
void myTask3(void *params)
{
char *str = (char*)params;
volatile int i;
static int counter = 0;
printf("%s. Executed task %d times.\n", str, ++counter);
for (i = 0; i < 100000; ++i);
osTaskDelay(5);
}
#ifdef X86_TEST_ENVIRONMENT
void* simulatedTimer(void* iarg)
{
uint8_t id = *( (uint8_t*) iarg );
volatile int j=0;
stick_this_thread_to_core(1);
printf("Thread %d starts.\n", id);
for (j = 0; j < 10e6; ++j);
printf("Thread %d finishs.\n", id);
//osRunScheduler();
}
void timerCallback(int signum)
{
static uint8_t cnt = 0;
static uint8_t ids[MAX_LEVEL_INT_NESTING];
static struct sched_param scheduling_params[MAX_LEVEL_INT_NESTING];
static struct sched_param probe1;
static int probe2 = 0;
int reture = 0;
static pthread_t threads[MAX_LEVEL_INT_NESTING];
if(cnt > (MAX_LEVEL_INT_NESTING-1))
{
//THROW_ERROR(E_MAX_LEVEL_INT_NESTING);
//exit(EXIT_FAILURE);
}
else
{
ids[cnt] = cnt;
scheduling_params[cnt].sched_priority = sched_get_priority_min(SCHED_FIFO) + cnt*2;
printf("Thread %d has priority %d.\n", cnt, scheduling_params[cnt].sched_priority);
pthread_create(&threads[cnt], NULL, &simulatedTimer, &ids[cnt]);
reture = pthread_setschedparam(threads[cnt], SCHED_FIFO, &scheduling_params[cnt]);
if(reture!=0)
printf("Error setting the priority: %d.\n", reture);
cnt++;
}
}
#endif
int main(void)
{
#ifdef X86_TEST_ENVIRONMENT
struct sigaction sa;
struct itimerval timer;
/* Install timer_handler as the signal handler for SIGVTALRM. */
memset (&sa, 0, sizeof (sa));
sa.sa_handler = &timerCallback;
sigaction (SIGVTALRM, &sa, NULL);
/* Configure the timer to expire after 250 msec... */
timer.it_value.tv_sec = 0;
timer.it_value.tv_usec = CLOCK_TICK_RATE_MS * 1000;
/* ... and every 250 msec after that. */
timer.it_interval.tv_sec = 0;
timer.it_interval.tv_usec = CLOCK_TICK_RATE_MS;
/* Start a virtual timer. It counts down whenever this process is executing. */
setitimer (ITIMER_VIRTUAL, &timer, NULL);
#endif
/* Add some tasks. */
osTaskCreate(&myTask1, "Task1", "This is Task1.", 1, NULL);
osTaskCreate(&myTask2, "Task2", "This is Task2.", 2, NULL);
osTaskCreate(&myTask3, "Task3", "This is Task3.", 3, NULL);
osPrintAllTasks();
#ifdef X86_TEST_ENVIRONMENT
/* Do busy work. */
while (1);
#endif
return 0;
}

47
software/os/ossettings.h

@ -0,0 +1,47 @@
#ifndef OS_SETTINGS_H
#define OS_SETTINGS_H
/* Error */
#define MAX_MESSAGE_SIZE 255
/* X86 */
//#define X86_TEST_ENVIRONMENT
/* Only needed for X86 simulation. */
#define MAX_LEVEL_INT_NESTING 3
/* Timing */
// TODO: Adjust this:
#define SYS_TICK_MS 1000
/* Don't adjust this ;) */
#if (SYS_TICK_MS <= 100)
#define SYS_TICK_PERIOD_MS SYS_TICK_MS
#else
#define SYS_TICK_PERIOD_MS 100
#endif
#define MS_2_TICKS(MS)\
(MS/SYS_TICK_PERIOD_MS)
#if (SYS_TICK_MS < 0)
#error "SYS_TICK_MS can not be smaller than 1."
#endif
#if ( (SYS_TICK_MS%1) != 0)
#error "SYS_TICK_MS has to be a natural number."
#endif
/* Scheduler */
// TODO: Adjust this:
#define MAX_SIZE_TASK_NAME 20
#define MAX_NUMBER_OF_TASKS 4
#define HEAP_SIZE 4
/* Don't adjust this ;) */
#if (MAX_NUMBER_OF_TASKS > HEAP_SIZE)
#warning "HEAP_SIZE < MAX_NUMER_OF_TASKS: This might lead to problems."
#endif
/* Alive LED */
#define ALIVE_PULSE_LENGTH MS_2_TICKS(200)
/* printf */
/* Convert every \n to \n\r */
#define CONVERT_NEWLINE
#endif

49
software/os/ostypes.h

@ -2,13 +2,16 @@
#define H_OS_TYPES
//--------------Includes-----------------
#include<stdint.h>
#include<settings.h>
#include "ossettings.h"
//--------------Scheduler----------------
/** Enum for scheduler state.
*/
*
*/
typedef enum
{
S_INIT,
@ -18,14 +21,16 @@ typedef enum
} osSchedulerState_t;
/** Enum for task states.
*/
*
*/
typedef enum
{
READY, RUNNING, SUSPENDED, BLOCKED
} osTaskState_t;
/** Struct representing the task control block.
*/
*
*/
typedef struct
{
void (*fnc_ptr)(void*);
@ -36,23 +41,47 @@ typedef struct
uint32_t wake_up;
} osTCB_t;
//--------------Errors-------------------
//--------------Errors & Warnings--------
/** Enum to hold all possible error codes.
*/
*
*/
typedef enum
{
E_MAX_NUMBER_OF_TASKS,
E_HEAP_OVERLFOW,
E_NULL_FORBIDDEN,
E_MAX_LEVEL_INT_NESTING
E_MAX_LEVEL_INT_NESTING,
E_BUFFER_OVERFLOW,
E_NULL_FORBIDDEN
} osError_t;
/** Enum to hold all possible warning codes.
*
*/
typedef enum
{
W_SYS_TIMER_OVERFLOW
} osWarning_t;
//--------------Heaps--------------------
/** Data type to hold a pointer to a TCB.
*/
*
*/
typedef osTCB_t* osHeapNode_t;
//--------------Queues-------------------
/** Data type holds a void pointer to an array to be able to use the queues for many data types.
*
*/
typedef struct
{
uint8_t write_p;
uint8_t read_p;
/* Gives you the possibility to use the q with every data type. */
void* start;
size_t varsize;
} osQUEUE_t;
#endif

44
software/os/printf.c

@ -12,9 +12,13 @@
#include "helpers.h"
#include "printf.h"
#include "../platform/usart.h"
#include "ossettings.h"
/** Increment index for a char buffer savely, preventing overflows.
*
* @param ioindex Index, that is supposed to be manipulated.
* @param ibuffsize Buffer size, which should not be exceeded.
* @retval 1 (SUCCESS) or 0 (FAILURE).
*/
static inline uint8_t osPreventBuffOv(uint* ioindex, size_t ibuffsize)
{
@ -27,8 +31,15 @@ static inline uint8_t osPreventBuffOv(uint* ioindex, size_t ibuffsize)
/** Parsing for floats within printf.
*
* @param iobuffer Buffer where the formated string ends up.
* @param ibuffsize Size of the iobuffer for security reasons.
* @param iformat Pointer to the format string from the user.
* @param i Pointer to the index where to write in the iobuffer.
* @param ifloat Float which shall be printed nicely.
* @param iflag Indicator if the user wants a certain amount of decimals.
* @retval Characters printed (SUCCESS) or -1 (FAILURE).
*/
static void osParseFloat(char* iobuffer, size_t ibuffsize, const char** iformat, uint* i, double ifloat, uint8_t flag)
static void osParseFloat(char* iobuffer, size_t ibuffsize, const char** iformat, uint* i, double ifloat, uint8_t iflag)
{
int temp_int;
size_t temp_buffsize;
@ -47,7 +58,7 @@ static void osParseFloat(char* iobuffer, size_t ibuffsize, const char** iformat,
iobuffer[*i] = temp_string[j];
osPreventBuffOv(i, ibuffsize);
}
if(!flag)
if(!iflag)
float_decimals = 4;
else
{
@ -76,13 +87,10 @@ static void osParseFloat(char* iobuffer, size_t ibuffsize, const char** iformat,
osPreventBuffOv(i, ibuffsize);
}
/* Get rid of the f. */
if(flag)
if(iflag)
(*iformat)++;
}
/** printf implementation where the magic happens.
*
*/
int osVPrintf(va_list iarguments, char* iobuffer, size_t ibuffsize, const char* iformat)
{
uint i = 0;
@ -150,6 +158,19 @@ int osVPrintf(va_list iarguments, char* iobuffer, size_t ibuffsize, const char*
}
else
{
/* If you are too lazy to always type \r\n */
#ifdef CONVERT_NEWLINE
if( (*iformat) == '\n' )
{
/* Copy \n */
iobuffer[i] = *iformat;
iformat++;
osPreventBuffOv(&i, ibuffsize);
/* Add \r */
iobuffer[i] = '\r';
osPreventBuffOv(&i, ibuffsize);
}
#endif
/* Copy characters into buffer. */
iobuffer[i] = *iformat;
iformat++;
@ -161,17 +182,6 @@ int osVPrintf(va_list iarguments, char* iobuffer, size_t ibuffsize, const char*
return (i+1);
}
/** printf to be used by the OS user. Can be ported to another platform easily
* by just using another function to transmit one string with the USART.
*
* @param iformat Currently supported are
%d integers
%c single characters
%s C strings
%f Floats with 4 decimals
%.xf Floats with x decimals
* @retval Returns the number of characters printed (SUCCESS) or -1 (FAILURE).
*/
int osPrintf(const char* iformat, ...)
{
va_list arguments;

23
software/os/printf.h

@ -8,11 +8,34 @@
#ifndef OS_PRINTF_H_
#define OS_PRINTF_H_
//--------------Includes-----------------
#include <stdio.h>
#include <stdarg.h>
#include "stm32f10x.h"
//--------------Funtions-----------------
/** printf to be used by the OS user. Can be ported to another platform easily
* by just using another function to transmit one string with the USART.
*
* @param iformat Currently supported are
%d integers
%c single characters
%s C strings
%f Floats with 4 decimals
%.xf Floats with x decimals
* @retval Returns the number of characters printed (SUCCESS) or -1 (FAILURE).
*/
int osPrintf(const char* iformat, ...);
/** printf implementation where the magic happens.
*
* @param iarguments Variable arguments list.
* @param iobuffer Buffer where the formated string ends up.
* @param ibuffsize Size of the iobuffer for security reasons.
* @param iformat Format string from the user.
* @retval Characters printed (SUCCESS) or -1 (FAILURE).
*/
int osVPrintf(va_list iarguments, char* iobuffer, size_t ibuffsize, const char* iformat);
#endif /* OS_PRINTF_H_ */

16
software/os/queues.h

@ -8,19 +8,15 @@
#ifndef OS_QUEUES_H_
#define OS_QUEUES_H_
#include "stm32f10x.h"
#include <stdlib.h>
//--------------Include------------------
#include<stm32f10x.h>
#include"ostypes.h"
#include<stdlib.h>
#define MAX_QUEUE_SIZE 64
typedef struct
{
uint8_t write_p;
uint8_t read_p;
/* Gives you the possibility to use the q with every data type. */
void* start;
size_t varsize;
} osQUEUE_t;
//--------------Functions----------------
void osQInit(osQUEUE_t* q, size_t ivarsize, void* istart);

197
software/os/scheduler.c

@ -1,11 +1,15 @@
//--------------Includes-----------------
#include<stdlib.h>
#include<stdio.h>
#include<stdint.h>
#include<string.h>
#include"scheduler.h"
#include"error.h"
#include"settings.h"
#include"heap.h"
#include"printf.h"
#include"ossettings.h"
#include"../platform/system_timer.h"
/* TCBs */
static osTCB_t tasks[MAX_NUMBER_OF_TASKS];
@ -19,18 +23,26 @@ static osHeapNode_t current = NULL;
/* Timing */
static uint32_t sys_clk = 0;
/* Queues */
/* Priority queues */
static osHeapNode_t ready_q[HEAP_SIZE];
/** Get the task which is running.
*
* @retval Pointer to TCB of the running task.
*/
static inline osTCB_t* osSchedulerGetRunningT(void)
{
for(int i=0; i<MAX_NUMBER_OF_TASKS; i++)
{
if(tasks[i].state == RUNNING)
return &tasks[i];
}
}
return NULL;
}
/** Initialize scheduler.
*
*/
static void osSchedulerInit(void)
{
/* A slot is defined empty when the fnc. pointer
@ -51,24 +63,25 @@ uint8_t osTaskCreate(void (*ifnc_ptr)(void*), char* itask_name, void* iarguments
/* Is enough memory available to create task?*/
if(task_cnt < MAX_NUMBER_OF_TASKS)
{
/* Check fo an empty slot. */
while(tasks[i].fnc_ptr != NULL)
i++;
/* Search for an empty slot. */
while(tasks[i].fnc_ptr != NULL)
i++;
/* Fill empty slot. */
tasks[i].fnc_ptr = ifnc_ptr;
strcpy(tasks[i].name, itask_name);
tasks[i].arguments = iarguments;
strcpy(tasks[i].name, itask_name);
tasks[i].arguments = iarguments;
tasks[i].priority = ipriority;
tasks[i].state = READY;
tasks[i].wake_up = 0;
if(oTaskHandle != NULL)
oTaskHandle = &(tasks[task_cnt]);
/* Increase number of tasks. */
task_cnt++;
osHeapInsert(ready_q, &tasks[i]);
return 1;
if(oTaskHandle != NULL)
oTaskHandle = &(tasks[task_cnt]);
/* Increase number of tasks. */
task_cnt++;
osHeapInsert(ready_q, &tasks[i]);
return 1;
}
else
THROW_ERROR(E_MAX_NUMBER_OF_TASKS);
THROW_ERROR(E_MAX_NUMBER_OF_TASKS);
return 0;
}
@ -80,6 +93,8 @@ void osTaskDelete(osTCB_t* iotask)
void osTaskDelay(uint8_t idelay)
{
osTCB_t* task_running = osSchedulerGetRunningT();
if( task_running == NULL )
THROW_ERROR(E_NULL_FORBIDDEN);
task_running->state = BLOCKED;
task_running->wake_up = sys_clk + idelay;
}
@ -87,66 +102,112 @@ void osTaskDelay(uint8_t idelay)
void osTaskDelayUntil(uint32_t iwakeup_time, uint8_t idelay)
{
osTCB_t* task_running = osSchedulerGetRunningT();
if( task_running == NULL )
THROW_ERROR(E_NULL_FORBIDDEN);
task_running->state = BLOCKED;
task_running->wake_up = iwakeup_time + idelay;
}
uint8_t osRunScheduler(void)
void osRunScheduler(void)
{
printf("System clock: %d\n", ++sys_clk);
/* Are any tasks becomming ready? */
for(int i=0; i<MAX_NUMBER_OF_TASKS; i++)
{
if( tasks[i].state == BLOCKED)
{
if(tasks[i].wake_up <= sys_clk)
{
/* Wake up task and put
it into ready queue. */
tasks[i].state = READY;
osHeapInsert(ready_q, &tasks[i]);
}
}
}
switch(state)
{
case S_INIT:
printf("S_INIT\n");
state = S_EXECUTING_NO_TASK;
break;
case S_EXECUTING_TASK:
printf("S_EXECUTING_TASK\n");
break;
case S_EXECUTING_NO_TASK:
printf("S_EXECUTING_NO_TASK\n");
/* Check if queue is empty. */
if(osHeapIsEmpty(ready_q))
{
state = S_IDELING;
break;
}
osHeapExtractMaximum(ready_q, &current);
current->state = RUNNING;
state = S_EXECUTING_TASK;
(*(current->fnc_ptr))(current->arguments);
state = S_EXECUTING_NO_TASK;
break;
case S_IDELING:
printf("S_IDELING\n");
if(!osHeapIsEmpty(ready_q))
state = S_EXECUTING_NO_TASK;
break;
}
uint32_t sys_clk_old = sys_clk;
static uint8_t flag = 0;
/* The Cortex-M3 system timer for instance
* can not handle a very high period needed
* e.g. for debugging as the register is
* simply too small. */
#if (SYS_TICK_MS >= 100)
static uint16_t cnt = 0;
if(cnt != SYS_TICK_MS/SYS_TICK_PERIOD_MS)
{
/* Don't execute scheduler. */
cnt++;
return;
}
else
cnt = 0;
#endif
osPrintf("System clock: %d\n", ++sys_clk);
if(sys_clk < sys_clk_old)
THROW_WARNING(W_SYS_TIMER_OVERFLOW);
if( (sys_clk % ALIVE_PULSE_LENGTH) == 0)
toggleAliveLED();
/* Are any tasks becomming ready? */
if(flag)
{
osPrintf("Hej!\n");
for(int i=0; i<MAX_NUMBER_OF_TASKS; i++)
{
if( tasks[i].state == BLOCKED)
{
if(tasks[i].wake_up <= sys_clk)
{
/* Wake up task and put
it into ready queue. */
tasks[i].state = READY;
osHeapInsert(ready_q, &tasks[i]);
}
}
}
}
else
{
osPrintf("Ho!\n");
for(int i=MAX_NUMBER_OF_TASKS; i>0; i--)
{
if( tasks[i].state == BLOCKED)
{
if(tasks[i].wake_up <= sys_clk)
{
/* Wake up task and put
it into ready queue. */
tasks[i].state = READY;
osHeapInsert(ready_q, &tasks[i]);
}
}
}
}
flag ^= 1;
switch(state)
{
case S_INIT:
osPrintf("S_INIT\n");
state = S_EXECUTING_NO_TASK;
break;
case S_EXECUTING_TASK:
osPrintf("S_EXECUTING_TASK\n");
break;
case S_EXECUTING_NO_TASK:
osPrintf("S_EXECUTING_NO_TASK\n");
/* Check if queue is empty. */
if(osHeapIsEmpty(ready_q))
{
state = S_IDELING;
break;
}
osHeapExtractMaximum(ready_q, &current);
current->state = RUNNING;
state = S_EXECUTING_TASK;
(*(current->fnc_ptr))(current->arguments);
state = S_EXECUTING_NO_TASK;
break;
case S_IDELING:
osPrintf("S_IDELING\n");
if(!osHeapIsEmpty(ready_q))
state = S_EXECUTING_NO_TASK;
break;
}
}
void osPrintTask(uint8_t index)
void osPrintTask(uint8_t iindex)
{
printf("Function Pointer:\t%p\n", tasks[index].fnc_ptr);
printf("Name:\t\t\t%s\n", tasks[index].name);
printf("Arguments Pointer:\t%p\n", tasks[index].fnc_ptr);
printf("Priority:\t\t%d\n", tasks[index].priority);
printf("State:\t\t\t%d\n", tasks[index].state);
printf("Wake up:\t\t%d\n", tasks[index].wake_up);
//osPrintf("Function Pointer:\t%d\n", tasks[iindex].fnc_ptr);
osPrintf("Name:\t\t\t%s\n", tasks[iindex].name);
//osPrintf("Arguments Pointer:\t%d\n", tasks[iindex].fnc_ptr);
//osPrintf("Priority:\t\t%d\n", tasks[iindex].priority);
//osPrintf("State:\t\t\t%d\n", tasks[iindex].state);
//osPrintf("Wake up:\t\t%d\n", tasks[iindex].wake_up);
}
void osPrintAllTasks(void)
@ -154,6 +215,6 @@ void osPrintAllTasks(void)
for(int i=0; i<MAX_NUMBER_OF_TASKS; i++)
{
osPrintTask(i);
printf("\n");
osPrintf("\n");
}
}

45
software/os/scheduler.h

@ -5,27 +5,58 @@
#include<stdlib.h>
#include<stdint.h>
#include"settings.h"
#include "ossettings.h"
#include"ostypes.h"
//--------------Functions----------------
static inline osTCB_t* osSchedulerGetRunningT(void);
static void osSchedulerInit(void);
// TODO: Schedule round robin when two or more tasks have the same priority.
/** Spawn a task.
*
* @param ifnc_ptr Pointer to the task function.
* @param itask_name Internal task name.
* @param iarguments Enables passing user-defined arguments to the task.
* @param ipriority A higher value means a higher priority of the task.
* @param oTaskHandle Pointer to TCB.
* @retval 1 (task has been spawned) or 0 (FAILED)
*/
uint8_t osTaskCreate(void (*ifnc_ptr)(void*), char* itask_name, void* iarguments, uint8_t ipriority, const osTCB_t* oTaskHandle);
/** Simply delete task by setting the function pointer to NULL.
*
* @param iotask Pointer to TCB.
*/
void osTaskDelete(osTCB_t* iotask);
/** Delay function. DO NOT USE FOR PERIODIC TASKS!
*
* @param idelay Delay in system ticks.
*/
void osTaskDelay(uint8_t idelay);
/** Delay until function. DO USE FOR PERIODIC TASKS!
*
* @param iwakeup_time Time when the task execution started.
* @param idelay Number of system ticks until the task shall be executed again.
*/
void osTaskDelayUntil(uint32_t iwakeup_time, uint8_t idelay);
uint8_t osRunScheduler(void);
/** System core. Scheduler needs to be executed by a timer interrupt.
*
*/
void osRunScheduler(void);
void osPrintTask(uint8_t index);
/** Print all information about one task.
*
* @param iindex Index in the TCB array.
*/
void osPrintTask(uint8_t iindex);
/** Print all information about all tasks.
*
*/
void osPrintAllTasks(void);
#endif

22
software/os/settings.h

@ -1,22 +0,0 @@
#ifndef OS_SETTINGS_H
#define OS_SETTINGS_H
/* Error */
#define MAX_MESSAGE_SIZE 255
/* Porting */
#define X86_TEST_ENVIRONMENT
/* Only needed for X86 simulation. */
#define MAX_LEVEL_INT_NESTING 3
/* Scheduler */
#define MAX_SIZE_TASK_NAME 20
#define MAX_NUMBER_OF_TASKS 4
#define CLOCK_TICK_RATE_MS 10
#define HEAP_SIZE 6
#if (MAX_NUMBER_OF_TASKS > HEAP_SIZE)
#warning "HEAP_SIZE < MAX_NUMER_OF_TASKS: This might lead to problems."
#endif
#endif

38
software/platform/system_timer.c

@ -5,15 +5,15 @@
* Author: maximilian
*/
#include "stm32f10x.h"
#include "stm32f10x_flash.h"
#include "stm32f10x_rcc.h"
//--------------Includes-----------------
#define ALIVE_PULSE_LENGTH 200
#include<stm32f10x.h>
#include<stm32f10x_flash.h>
#include<stm32f10x_rcc.h>
#include"../os/scheduler.h"
#include"../os/ossettings.h"
static volatile uint32_t ticky = 0;
void InitAliveLED(void)
void initAliveLED(void)
{
/* Activate clock for peripheral. */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
@ -27,7 +27,14 @@ void InitAliveLED(void)
GPIO_Init (GPIOA , & GPIO_InitStructure );
}
void InitClock(void)
void toggleAliveLED(void)
{
static volatile uint8_t led_stat = 0;
led_stat = !led_stat;
GPIO_WriteBit(GPIOA, GPIO_Pin_5, led_stat);
}
void initClock(void)
{
/* Configure all clocks to max for best performance.
If there are EMI, power, or noise problems, try slowing the clocks.*/
@ -51,20 +58,13 @@ void InitClock(void)
RCC_PCLK1Config(RCC_HCLK_Div8);
RCC_PCLK2Config(RCC_HCLK_Div8);
/* Configure Cortex-M System Tick Timer to tick every ms.*/
/* Configure Cortex-M System Tick Timer to tick as the os user defined.*/
SystemCoreClockUpdate();
SysTick_Config(SystemCoreClock / 1000);
SysTick_Config( (SystemCoreClock/1000) * SYS_TICK_PERIOD_MS );
}
void SysTick_Handler(void)
{
static volatile uint8_t led_stat = 0;
if(ticky == ALIVE_PULSE_LENGTH)
{
led_stat = !led_stat;
GPIO_WriteBit(GPIOA, GPIO_Pin_5, led_stat);
ticky = 0;
}
else
ticky++;
// TODO: For porting use another timer here to call the scheduler.
osRunScheduler();
}

5
software/platform/system_timer.h

@ -8,7 +8,8 @@
#ifndef PLATFORM_SYSTEM_TIMER_H_
#define PLATFORM_SYSTEM_TIMER_H_
void InitAliveLED(void);
void InitClock(void);
void initAliveLED(void);
void toggleAliveLED(void);
void initClock(void);
#endif /* PLATFORM_SYSTEM_TIMER_H_ */

Loading…
Cancel
Save