OCEOS Tutorials: Difference between revisions
Backup20261021>Dtimofejevs |
m 1 revision imported |
(No difference)
| |
Latest revision as of 10:47, 28 October 2026
Tutorials
Introduction
This section presents some typical real-time tasks and how they can be addressed using OCEOS.
Getting started
Section 9.5 provides guidance on how to structure an OCEOS application. The file asw.c provided with OCEOS is a simple example.
The directives to initialise and start OCEOS are:
- application_init – Initialise fixed data and start system timer(s)
- oceos_task_create - Create task setting priority, no of jobs, ..etc.
- oceos_init_finish – Initilise dynamic data area
- oceos_start – Start the scheduler and pass control to first task
After steps 1 to 4 above tasks implement application functionality. If mutexes, semaphores, or dataqs are required they are also created at step 2.
Note: it is mandatory to create the number of mutexes, semaphores, and dataqs declared otherwise oceos_init_finish() will return an error.
Tutorials
Tutorial 1 – Starting tasks
This exercise demonstrates starting tasks with different priorities.
- Two tasks, one higher priority (i.e. lower priority value), one lower priority (i.e. higher priority value. Each task allowed to have up to two concurrent jobs.
- Each task outputs a message when it starts, another message when it exits.
- Start OCEOS with the low priority task.
- This starts the high priority task and then exits.
- The high priority task starts the low priority tasks and exits.
For code example see below.
tut.h
/*
*********************************************************************************************************
* OCEOS
* Real-Time Operating System
* for
* ARM Microcontroller
*
* Example implementation of OCEOS
*
*
* (c) Copyright 2021, O.C.E. Technology
* All Rights Reserved
*
*
* Author: jfk
********************************************************************************************************
*/
#ifndef TUT1_H_
#define TUT1_H_
/* Sample Task names - all here start with t_ to help avoid name confusion */
enum TASK_NAME{
t_0, // High priority task
t_1 // Low priority task
};
char* nullPtr = ""; // Need pointer to pass to oceos_start
void (*nullFun)(void *); // Null function
/*
* APPLICATION FUNCTION DECLARATIONS
*/
void fun0(void *);
void fun1(void *);
#endif /* TUT1_H_ */
oceos_config.h
/*
*********************************************************************************************************
* OCEOS
* Real-Time Operating System
* for
* ARM Microcontroller
*
* Example implementation of OCEOS
*
*
* (c) Copyright 2021, O.C.E. Technology
* All Rights Reserved
*
*
* Author: jfk
********************************************************************************************************
*/
#ifndef INCLUDE_OCEOS_CONFIG_H_
#define INCLUDE_OCEOS_CONFIG_H_
// 1: Includes OCEOS main header file
#include "oceos.h"
//----------------------------------------------------------------------------
// 2: Number of Log entries.
#define NUMBER_OF_LOG_ENTRIES 64 // 16 to 1024, default 64
//----------------------------------------------------------------------------
// 3: Number of tasks
#define NUMBER_OF_TASKS 2 // 1 to 255
//----------------------------------------------------------------------------
// 4: Number of ready queue entries, 0 to 254, see manual( MUST BE UPDATED BY USER);
// Defaults to number of tasks, as each task should have aa least one job;
// If Number of ready Q entries larger that number of total jobs => defaults to number of total jobs
#define NUMBER_OF_READYQ_ENTRIES NUMBER_OF_TASKS * 2
//----------------------------------------------------------------------------
// 5: Number of Mutexes
#define NUMBER_OF_MUTEXES 0 // 0 to 63
//----------------------------------------------------------------------------
// 6: Number of Semaphores
#define NUMBER_OF_SEMAPHORES 0 // 0 to 63
//----------------------------------------------------------------------------
// 7: Number of Data Qs
#define NUMBER_OF_DATAQS 0 // 0 to 63
//----------------------------------------------------------------------------
// 8: LOG data array size
#define LOG_DATA_ARRAY_SIZE_U32S 0x88// Calculated value. Read manual
//----------------------------------------------------------------------------
// 9: FIXED data array size
#define FIXED_DATA_ARRAY_SIZE_U32S 0x32// Calculated value. Read manual
//----------------------------------------------------------------------------
// 10: DYNAMIC data array size
#define DYN_DATA_ARRAY_SIZE_U32S 0x33// Calculated value. Read manual
//----------------------------------------------------------------------------
// 11: Timed Actions
#define NUMBER_OF_ACTION_ENTRIES 0 // User-modify field
//----------------------------------------------------------------------------
// 12: Log entries base 2
#define CS_LOG_DEF_ENTRIES_BASE2 0
//----------------------------------------------------------------------------
// 13: OCEOS stack start Address
#define OCEOS_STACK_START_ADDRESS 0
//----------------------------------------------------------------------------
// 14: OCEOS stack end address
#define OCEOS_STACK_LOW_BOUND_ADDRESS 0
//----------------------------------------------------------------------------
/**
* Target specific configurations
*/
/*
* ARM specific configurations
*/
#ifdef __SAM3X8E__
#ifndef BSP_SYSFREQ
#define BSP_SYSFREQ 84 // ARM target frequency in Mhz
#endif
#endif
#ifdef __SAMV71Q21__
#ifndef BSP_SYSFREQ
#define BSP_SYSFREQ 300 // ARM target frequency in Mhz
#endif
#endif
#ifdef __VA41620__
#ifndef BSP_SYSFREQ
#define BSP_SYSFREQ 100 // ARM target frequency in Mhz
#endif
#endif
//--------------------------------------------------------------------
// User defined function to deal with system errors
void oceos_on_error(void);
//---------------------------------------------------------------------
// User defined function to deal with log 2/3 full
void oceos_on_full_log(void);
//---------------------------------------------------------------------
extern U32_t log_data[];
extern U32_t fixed_data[];
extern U32_t dynamic_data[];
extern const unsigned int __oceos_bsp_sysfreq;
/**
* Initialize OCEOS with user configurations
*/
int application_init(void);
#endif /* INCLUDE_OCEOS_CONFIG_H_ */
oceos_config.c
/*
*********************************************************************************************************
* OCEOS
* Real-Time Operating System
* for
* ARM Microcontroller
*
* Example implementation of OCEOS
*
*
* (c) Copyright 2021, O.C.E. Technology
* All Rights Reserved
*
*
* Author: jfk
********************************************************************************************************
*/
#include <stdio.h>
#include "oceos_config.h"
/*
* OCEOS INTERNAL DATA STORAGE
*
* This application defines arrays to hold OCEOS internal data.
* The array sizes are provided by DMON by running "oceos info" command:</br>
* *Set all three arrays to guessed max zise, run application for the first time and exit.</br>
* *Run DMON command "oceos info" to get size for each array.</br>
* *Update array sizes below
*/
U32_t log_data[LOG_DATA_ARRAY_SIZE_U32S];
U32_t fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; // will be in data segment
U32_t dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];
const unsigned int __oceos_bsp_sysfreq = BSP_SYSFREQ * 1000 * 1000;// TODO
static BOOLE_t log_full_was_called = FALSE;
/**
* Must be defined if Application is using :
* Dataq with timeout
* Semaphore with timeout
* Timed Actions
*/
/*
* Set up the application configuration structure and pass it to oceos_init
* (done this way the memory used for the structure is returned automatically)
*/
int application_init(){
/*
* Create the application configuration structure
*/
struct application_configuration app_config = {0};
/*
* Fill in the application parameters
*/
app_config.log_address = (adrs_t)log_data; // required
app_config.fixed_data_address = (adrs_t)fixed_data; // required
app_config.dynamic_data_address = (adrs_t)dynamic_data; // required
app_config.stack_start_address = OCEOS_STACK_START_ADDRESS; // 0 => no check
app_config.stack_lower_bound_address = OCEOS_STACK_LOW_BOUND_ADDRESS; // 0 => no check
app_config.system_error_function = &oceos_on_error; // NULL => ignore
app_config.log_full_function = &oceos_on_full_log; // NULL => ignore
// used in setting up system log and fixed data array
app_config.log_number_of_entries = NUMBER_OF_LOG_ENTRIES; // 0 => use default
app_config.number_of_tasks = NUMBER_OF_TASKS; // >= 1
app_config.number_of_readyQ_entries = NUMBER_OF_READYQ_ENTRIES; // 0 => calculate size
app_config.number_of_mutexes = NUMBER_OF_MUTEXES;
app_config.number_of_counting_semaphores = NUMBER_OF_SEMAPHORES;
app_config.number_of_data_queues = NUMBER_OF_DATAQS;
app_config.timed_actions_queue_size = NUMBER_OF_ACTION_ENTRIES;
app_config.CS_log_entries_base2 = CS_LOG_DEF_ENTRIES_BASE2;
app_config.use_oceos_system_time = TRUE;
// initialise OCEOS
enum DIRECTIVE_STATUS status;
status = oceos_init(app_config);
if (SUCCESSFUL == status) {
return 1;
} else {
printf("\n oceos_init failure\n");
return -1;
} // else
} // application_init()
/**
* User to implement in case of system error;
* Comment it out if not used and set field system_error_function in app_config to NULL
*/
void oceos_on_error() {
return;
}
/**
* User to implement in case of system log is 2/3 full;
* Comment it out if not used and set field log_full_function in app_config to NULL
*/
void oceos_on_full_log(){
log_full_was_called = TRUE;
return;
}
tut1.c
/*
*********************************************************************************************************
* OCEOS
* Real-Time Operating System
* for
* ARM Microcontroller
*
* Example implementation of OCEOS
*
*
* (c) Copyright 2021, O.C.E. Technology
* All Rights Reserved
*
*
* Author: jfk
********************************************************************************************************
*/
#include <stdio.h>
#include <stdlib.h>
#include "tut1.h" // application header
#include "oceos_config.h" // OCEOS header
int main(void) {
int status;
/*
* Initialise the application configuration and OCEOS
*
* This application function creates the application configuration
* and passes it to oceos_init(), which initialises the fixed data
* and enables the system log
*/
if (!application_init()) {
//LOG
return -1;
}
// Create Main task to
if (oceos_task_create(t_0,// taskID, used as index, must be in range 0 to 254
100,// priority, must be in range 1 to 254, lower value is higher priority
100, // threshold, must be in range 1 to task priority
2, // jobs_max, must be in range 1 to 15
0,// FALSE -> floating point hardware not used by task
1, // FALSE -> task initially not enabled
fun0, // main body of task
nullFun, // task end function
0,// time_deadline, must finish no later than this after start, 0 => ignore
0 // minimum time expected between start requests, 0 => no restriction
) != SUCCESSFUL)
return 1;
if (oceos_task_create(t_1, 200, 200, 2, 0, 1, fun1, nullFun, 0, 0)
!= SUCCESSFUL)
return 2;
/*
* Finish initialising OCEOS and setting up the fixed data
*/
status = oceos_init_finish();
if (SUCCESSFUL != status) {
return 3;
} // if
/*
* Start OCEOS scheduling
*
* The OCEOS fixed data provides all the information required.
*
* If a valid task is specified, it is started and passed the pointer.
* Otherwise the system is put in sleep mode
*/
status = oceos_start(fixed_data, t_1, (void*) nullPtr); // Start OCEOS with lower prioroty task
return status;
} // main
/*
* Application code functions, functions declared in asw.h
*/
void fun0(void *ptr) {
printf("Entered high priority task\n");
oceos_task_start(t_1, ptr);
printf("Leaving high priority task\n");
return;
} // fun0()
void fun1(void *ptr) {
printf("Entered low priority task\n");
oceos_task_start(t_0, ptr);
printf("Leaving low priority task\n");
return;
} // fun1()
Tutorial 2 – Using a mutex
This exercise will familiarise the developer with the use a mutexes.
- Two tasks as before.
- One mutex. Note the priority ceiling of the mutex.
- Both tasks output message when they get the mutex and when they return it
- Start OCEOS with the low priority task
- This grabs mutex, then starts high priority task
- Low priority task returns mutex then exits
- High priority task returns mutex, start low priority task and exits
For code example see example below:
tut2.h
/*
*********************************************************************************************************
* OCEOS
* Real-Time Operating System
* for
* ARM Microcontroller
*
* Example implementation of OCEOS
*
*
* (c) Copyright 2021, O.C.E. Technology
* All Rights Reserved
*
*
* Author: jfk
********************************************************************************************************
*/
#ifndef TUT2_H_
#define TUT2_H_
/* Sample Task names - all here start with t_ to help avoid name confusion */
enum TASK_NAME{
t_0, // High priority task
t_1 // Low priority task
};
/* Sample Mutex names - all here start with m_ to help avoid name confusion */
enum MUTEX_NAME{
m_0
};
char* nullPtr = ""; // Need pointer to pass to oceos_start
void (*nullFun)(void *); // Null function
/*
* APPLICATION FUNCTION DECLARATIONS
*/
void fun0(void *);
void fun1(void *);
#endif /* TUT2_H_ */
oceos_config.h
/*
*********************************************************************************************************
* OCEOS
* Real-Time Operating System
* for
* ARM Microcontroller
*
* Example implementation of OCEOS
*
*
* (c) Copyright 2021, O.C.E. Technology
* All Rights Reserved
*
*
* Author: jfk
********************************************************************************************************
*/
#ifndef INCLUDE_OCEOS_CONFIG_H_
#define INCLUDE_OCEOS_CONFIG_H_
// 1: Includes OCEOS main header file
#include "oceos.h"
//----------------------------------------------------------------------------
// 2: Number of Log entries.
#define NUMBER_OF_LOG_ENTRIES 64 // 16 to 1024, default 64
//----------------------------------------------------------------------------
// 3: Number of tasks
#define NUMBER_OF_TASKS 2 // 1 to 255
//----------------------------------------------------------------------------
// 4: Number of ready queue entries, 0 to 254, see manual( MUST BE UPDATED BY USER);
// Defaults to number of tasks, as each task should have aa least one job;
// If Number of ready Q entries larger that number of total jobs => defaults to number of total jobs
#define NUMBER_OF_READYQ_ENTRIES NUMBER_OF_TASKS * 2
//----------------------------------------------------------------------------
// 5: Number of Mutexes
#define NUMBER_OF_MUTEXES 1 // 0 to 63
//----------------------------------------------------------------------------
// 6: Number of Semaphores
#define NUMBER_OF_SEMAPHORES 0 // 0 to 63
//----------------------------------------------------------------------------
// 7: Number of Data Qs
#define NUMBER_OF_DATAQS 0 // 0 to 63
//----------------------------------------------------------------------------
// 8: LOG data array size
#define LOG_DATA_ARRAY_SIZE_U32S 0x88// Calculated value. Read manual
//----------------------------------------------------------------------------
// 9: FIXED data array size
#define FIXED_DATA_ARRAY_SIZE_U32S 0x33// Calculated value. Read manual
//----------------------------------------------------------------------------
// 10: DYNAMIC data array size
#define DYN_DATA_ARRAY_SIZE_U32S 0x34// Calculated value. Read manual
//----------------------------------------------------------------------------
// 11: Timed Actions
#define NUMBER_OF_ACTION_ENTRIES 0 // User-modify field
//----------------------------------------------------------------------------
// 12: Log entries base 2
#define CS_LOG_DEF_ENTRIES_BASE2 0
//----------------------------------------------------------------------------
// 13: OCEOS stack start Address
#define OCEOS_STACK_START_ADDRESS 0
//----------------------------------------------------------------------------
// 14: OCEOS stack end address
#define OCEOS_STACK_LOW_BOUND_ADDRESS 0
//----------------------------------------------------------------------------
/**
* Target specific configurations
*/
/*
* ARM specific configurations
*/
#ifdef __SAM3X8E__
#ifndef BSP_SYSFREQ
#define BSP_SYSFREQ 84 // ARM target frequency in Mhz
#endif
#endif
#ifdef __SAMV71Q21__
#ifndef BSP_SYSFREQ
#define BSP_SYSFREQ 300 // ARM target frequency in Mhz
#endif
#endif
#ifdef __VA41620__
#ifndef BSP_SYSFREQ
#define BSP_SYSFREQ 100 // ARM target frequency in Mhz
#endif
#endif
//--------------------------------------------------------------------
// User defined function to deal with system errors
void oceos_on_error(void);
//---------------------------------------------------------------------
// User defined function to deal with log 2/3 full
void oceos_on_full_log(void);
//---------------------------------------------------------------------
extern U32_t log_data[];
extern U32_t fixed_data[];
extern U32_t dynamic_data[];
extern const unsigned int __oceos_bsp_sysfreq;
/**
* Initialize OCEOS with user configurations
*/
int application_init(void);
#endif /* INCLUDE_OCEOS_CONFIG_H_ */
oceos_config.c
/*
*********************************************************************************************************
* OCEOS
* Real-Time Operating System
* for
* ARM Microcontroller
*
* Example implementation of OCEOS
*
*
* (c) Copyright 2021, O.C.E. Technology
* All Rights Reserved
*
*
* Author: jfk
********************************************************************************************************
*/
#include <stdio.h>
#include "oceos_config.h"
/*
* OCEOS INTERNAL DATA STORAGE
*
* This application defines arrays to hold OCEOS internal data.
* The array sizes are provided by DMON by running "oceos info" command:</br>
* *Set all three arrays to guessed max zise, run application for the first time and exit.</br>
* *Run DMON command "oceos info" to get size for each array.</br>
* *Update array sizes below
*/
U32_t log_data[LOG_DATA_ARRAY_SIZE_U32S];
U32_t fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; // will be in data segment
U32_t dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];
const unsigned int __oceos_bsp_sysfreq = BSP_SYSFREQ * 1000 * 1000;// TODO
static BOOLE_t log_full_was_called = FALSE;
/**
* Must be defined if Application is using :
* Dataq with timeout
* Semaphore with timeout
* Timed Actions
*/
/*
* Set up the application configuration structure and pass it to oceos_init
* (done this way the memory used for the structure is returned automatically)
*/
int application_init(){
/*
* Create the application configuration structure
*/
struct application_configuration app_config = {0};
/*
* Fill in the application parameters
*/
app_config.log_address = (adrs_t)log_data; // required
app_config.fixed_data_address = (adrs_t)fixed_data; // required
app_config.dynamic_data_address = (adrs_t)dynamic_data; // required
app_config.stack_start_address = OCEOS_STACK_START_ADDRESS; // 0 => no check
app_config.stack_lower_bound_address = OCEOS_STACK_LOW_BOUND_ADDRESS; // 0 => no check
app_config.system_error_function = &oceos_on_error; // NULL => ignore
app_config.log_full_function = &oceos_on_full_log; // NULL => ignore
// used in setting up system log and fixed data array
app_config.log_number_of_entries = NUMBER_OF_LOG_ENTRIES; // 0 => use default
app_config.number_of_tasks = NUMBER_OF_TASKS; // >= 1
app_config.number_of_readyQ_entries = NUMBER_OF_READYQ_ENTRIES; // 0 => calculate size
app_config.number_of_mutexes = NUMBER_OF_MUTEXES;
app_config.number_of_counting_semaphores = NUMBER_OF_SEMAPHORES;
app_config.number_of_data_queues = NUMBER_OF_DATAQS;
app_config.timed_actions_queue_size = NUMBER_OF_ACTION_ENTRIES;
app_config.CS_log_entries_base2 = CS_LOG_DEF_ENTRIES_BASE2;
app_config.use_oceos_system_time = TRUE;
// initialise OCEOS
enum DIRECTIVE_STATUS status;
status = oceos_init(app_config);
if (SUCCESSFUL == status) {
return 1;
} else {
printf("\n oceos_init failure\n");
return -1;
} // else
} // application_init()
/**
* User to implement in case of system error;
* Comment it out if not used and set field system_error_function in app_config to NULL
*/
void oceos_on_error() {
return;
}
/**
* User to implement in case of system log is 2/3 full;
* Comment it out if not used and set field log_full_function in app_config to NULL
*/
void oceos_on_full_log(){
log_full_was_called = TRUE;
return;
}
tut2.c
/*
*********************************************************************************************************
* OCEOS
* Real-Time Operating System
* for
* ARM Microcontroller
*
* Example implementation of OCEOS
*
*
* (c) Copyright 2021, O.C.E. Technology
* All Rights Reserved
*
*
* Author: jfk
********************************************************************************************************
*/
#include <stdio.h>
#include <stdlib.h>
#include "tut2.h" // application header
/* N.B. Application header is included first */
#include "oceos_config.h" // OCEOS header for this application
#include "mutex.h"
int main(void) {
int status;
/*
* Initialise the application configuration and OCEOS
*
* This application function creates the application configuration
* and passes it to oceos_init(), which initialises the fixed data
* and enables the system log
*/
if (!application_init()) {
//LOG
return -1;
}
// Create Main task to
if (oceos_task_create(t_0,// taskID, used as index, must be in range 0 to 254
100,// priority, must be in range 1 to 254, lower value is higher priority
100, // threshold, must be in range 1 to task priority
2, // jobs_max, must be in range 1 to 15
0,// FALSE -> floating point hardware not used by task
1, // FALSE -> task initially not enabled
fun0, // main body of task
nullFun, // task end function
0,// time_deadline, must finish no later than this after start, 0 => ignore
0 // minimum time expected between start requests, 0 => no restriction
) != SUCCESSFUL)
return 1;
if (oceos_task_create(t_1, 200, 200, 2, 0, 1, fun1, nullFun, 0, 0)
!= SUCCESSFUL)
return 2;
if (oceos_mutex_create(m_0, 100) != SUCCESSFUL) // Create mutex with ceiling of highest priority task using it
return 3;
/*
* Finish initialising OCEOS and setting up the fixed data
*/
status = oceos_init_finish();
if (SUCCESSFUL != status) {
return 4;
} // if
/*
* Start OCEOS scheduling
*
* The OCEOS fixed data provides all the information required.
*
* If a valid task is specified, it is started and passed the pointer.
* Otherwise the system is put in sleep mode
*/
status = oceos_start(fixed_data, t_1, (void*) nullPtr); // Start OCEOS with lower prioroty task
return status;
} // main
/*
* Application code functions, functions declared in asw.h
*/
void fun0(void *ptr) {
if (oceos_mutex_wait(m_0) != SUCCESSFUL) {
printf("Error from high priority task getting mutex\n");
} else {
printf("high priority task got mutex\n");
}
oceos_task_start(t_1, ptr); // Start lower priority task
if (oceos_mutex_signal(m_0) != SUCCESSFUL) {
printf("Error from high priority task releasing mutex\n");
} else {
printf("High priority task released mutex\n");
}
return;
} // fun0()
void fun1(void *ptr) {
if (oceos_mutex_wait(m_0) != SUCCESSFUL) {
printf("Error from low priority task getting mutex\n");
} else {
printf("Low priority task got mutex\n");
}
oceos_task_start(t_0, ptr); // Start higher priority task
if (oceos_mutex_signal(m_0) != SUCCESSFUL) {
printf("Error from low priority task releasing mutex\n");
} else {
printf("Low priority task released mutex\n");
}
return;
} // fun1()
Tutorial 3 – Using Semaphores
Semaphores can be used to synchronise task actions as in this exercise.
- Three tasks this time, one high priority and the other two with the same lower priority
- Two counting semaphores, one initially 0, one initially 4, called ‘items’ and ‘spaces’
- First task starts second and third tasks
- Second task loops
- wait_restart spaces
- signal items
- Output ‘item done’ message
- Third task loops
- wait_restart items
- Output ‘got item’ message
- signal spaces
For code example see below:
tut3.h
/*
*********************************************************************************************************
* OCEOS
* Real-Time Operating System
* for
* ARM Microcontroller
*
* Example implementation of OCEOS
*
*
* (c) Copyright 2021, O.C.E. Technology
* All Rights Reserved
*
*
* Author: jfk
********************************************************************************************************
*/
#ifndef TUT3_H_
#define TUT3_H_
/* Sample Task names - all here start with t_ to help avoid name confusion */
enum TASK_NAME{
t_0, // Task to start other two
t_1, // consumer task
t_2 // consumer task
};
/* Sample Counting Semaphore names - all here start with s_ to help avoid name confusion */
enum SEM_NAME{
items, // Semaphore called items
spaces // Semaphore called spaces
};
char* nullPtr = ""; // Need pointer to pass to oceos_start
void (*nullFun)(void *); // Null function
/*
* APPLICATION FUNCTION DECLARATIONS
*/
void fun0(void *);
void fun1(void *);
void fun2(void *);
#endif /* TUT3_H_ */
oceos_config.h
/*
*********************************************************************************************************
* OCEOS
* Real-Time Operating System
* for
* ARM Microcontroller
*
* Example implementation of OCEOS
*
*
* (c) Copyright 2021, O.C.E. Technology
* All Rights Reserved
*
*
* Author: jfk
********************************************************************************************************
*/
#ifndef INCLUDE_OCEOS_CONFIG_H_
#define INCLUDE_OCEOS_CONFIG_H_
// 1: Includes OCEOS main header file
#include "oceos.h"
//----------------------------------------------------------------------------
// 2: Number of Log entries.
#define NUMBER_OF_LOG_ENTRIES 64 // 16 to 1024, default 64
//----------------------------------------------------------------------------
// 3: Number of tasks
#define NUMBER_OF_TASKS 3 // 1 to 255
//----------------------------------------------------------------------------
// 4: Number of ready queue entries, 0 to 254, see manual( MUST BE UPDATED BY USER);
// Defaults to number of tasks, as each task should have aa least one job;
// If Number of ready Q entries larger that number of total jobs => defaults to number of total jobs
#define NUMBER_OF_READYQ_ENTRIES NUMBER_OF_TASKS * 2
//----------------------------------------------------------------------------
// 5: Number of Mutexes
#define NUMBER_OF_MUTEXES 0 // 0 to 63
//----------------------------------------------------------------------------
// 6: Number of Semaphores
#define NUMBER_OF_SEMAPHORES 2 // 0 to 63
//----------------------------------------------------------------------------
// 7: Number of Data Qs
#define NUMBER_OF_DATAQS 0 // 0 to 63
//----------------------------------------------------------------------------
// 8: LOG data array size
#define LOG_DATA_ARRAY_SIZE_U32S 0x88// Calculated value. Read manual
//----------------------------------------------------------------------------
// 9: FIXED data array size
#define FIXED_DATA_ARRAY_SIZE_U32S 0x3a// Calculated value. Read manual
//----------------------------------------------------------------------------
// 10: DYNAMIC data array size
#define DYN_DATA_ARRAY_SIZE_U32S 0x65// Calculated value. Read manual
//----------------------------------------------------------------------------
// 11: Timed Actions
#define NUMBER_OF_ACTION_ENTRIES 0 // User-modify field
//----------------------------------------------------------------------------
// 12: Log entries base 2
#define CS_LOG_DEF_ENTRIES_BASE2 0
//----------------------------------------------------------------------------
// 13: OCEOS stack start Address
#define OCEOS_STACK_START_ADDRESS 0
//----------------------------------------------------------------------------
// 14: OCEOS stack end address
#define OCEOS_STACK_LOW_BOUND_ADDRESS 0
//----------------------------------------------------------------------------
/**
* Target specific configurations
*/
/*
* ARM specific configurations
*/
#ifdef __SAM3X8E__
#ifndef BSP_SYSFREQ
#define BSP_SYSFREQ 84 // ARM target frequency in Mhz
#endif
#endif
#ifdef __SAMV71Q21__
#ifndef BSP_SYSFREQ
#define BSP_SYSFREQ 300 // ARM target frequency in Mhz
#endif
#endif
#ifdef __VA41620__
#ifndef BSP_SYSFREQ
#define BSP_SYSFREQ 100 // ARM target frequency in Mhz
#endif
#endif
//--------------------------------------------------------------------
// User defined function to deal with system errors
void oceos_on_error(void);
//---------------------------------------------------------------------
// User defined function to deal with log 2/3 full
void oceos_on_full_log(void);
//---------------------------------------------------------------------
extern U32_t log_data[];
extern U32_t fixed_data[];
extern U32_t dynamic_data[];
extern const unsigned int __oceos_bsp_sysfreq;
/**
* Initialize OCEOS with user configurations
*/
int application_init(void);
#endif /* INCLUDE_OCEOS_CONFIG_H_ */
oceos_config.c
/*
*********************************************************************************************************
* OCEOS
* Real-Time Operating System
* for
* ARM Microcontroller
*
* Example implementation of OCEOS
*
*
* (c) Copyright 2021, O.C.E. Technology
* All Rights Reserved
*
*
* Author: jfk
********************************************************************************************************
*/
#include <stdio.h>
#include "oceos_config.h"
/*
* OCEOS INTERNAL DATA STORAGE
*
* This application defines arrays to hold OCEOS internal data.
* The array sizes are provided by DMON by running "oceos info" command:</br>
* *Set all three arrays to guessed max zise, run application for the first time and exit.</br>
* *Run DMON command "oceos info" to get size for each array.</br>
* *Update array sizes below
*/
U32_t log_data[LOG_DATA_ARRAY_SIZE_U32S];
U32_t fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; // will be in data segment
U32_t dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];
const unsigned int __oceos_bsp_sysfreq = BSP_SYSFREQ * 1000 * 1000;// TODO
static BOOLE_t log_full_was_called = FALSE;
/**
* Must be defined if Application is using :
* Dataq with timeout
* Semaphore with timeout
* Timed Actions
*/
/*
* Set up the application configuration structure and pass it to oceos_init
* (done this way the memory used for the structure is returned automatically)
*/
int application_init(){
/*
* Create the application configuration structure
*/
struct application_configuration app_config = {0};
/*
* Fill in the application parameters
*/
app_config.log_address = (adrs_t)log_data; // required
app_config.fixed_data_address = (adrs_t)fixed_data; // required
app_config.dynamic_data_address = (adrs_t)dynamic_data; // required
app_config.stack_start_address = OCEOS_STACK_START_ADDRESS; // 0 => no check
app_config.stack_lower_bound_address = OCEOS_STACK_LOW_BOUND_ADDRESS; // 0 => no check
app_config.system_error_function = &oceos_on_error; // NULL => ignore
app_config.log_full_function = &oceos_on_full_log; // NULL => ignore
// used in setting up system log and fixed data array
app_config.log_number_of_entries = NUMBER_OF_LOG_ENTRIES; // 0 => use default
app_config.number_of_tasks = NUMBER_OF_TASKS; // >= 1
app_config.number_of_readyQ_entries = NUMBER_OF_READYQ_ENTRIES; // 0 => calculate size
app_config.number_of_mutexes = NUMBER_OF_MUTEXES;
app_config.number_of_counting_semaphores = NUMBER_OF_SEMAPHORES;
app_config.number_of_data_queues = NUMBER_OF_DATAQS;
app_config.timed_actions_queue_size = NUMBER_OF_ACTION_ENTRIES;
app_config.CS_log_entries_base2 = CS_LOG_DEF_ENTRIES_BASE2;
app_config.use_oceos_system_time = TRUE;
// initialise OCEOS
enum DIRECTIVE_STATUS status;
status = oceos_init(app_config);
if (SUCCESSFUL == status) {
return 1;
} else {
printf("\n oceos_init failure\n");
return -1;
} // else
} // application_init()
/**
* User to implement in case of system error;
* Comment it out if not used and set field system_error_function in app_config to NULL
*/
void oceos_on_error() {
return;
}
/**
* User to implement in case of system log is 2/3 full;
* Comment it out if not used and set field log_full_function in app_config to NULL
*/
void oceos_on_full_log(){
log_full_was_called = TRUE;
return;
}
tut3.c
/*
*********************************************************************************************************
* OCEOS
* Real-Time Operating System
* for
* ARM Microcontroller
*
* Example implementation of OCEOS
*
*
* (c) Copyright 2021, O.C.E. Technology
* All Rights Reserved
*
*
* Author: jfk
********************************************************************************************************
*/
#include <stdio.h>
#include <stdlib.h>
/* N.B. Application header is included first */
#include "oceos_config.h" // OCEOS header for this application
#include "tut3.h" // application header
#include "semaphore.h"
int main(void) {
int status;
/*
* Initialise the application configuration and OCEOS
*
* This application function creates the application configuration
* and passes it to oceos_init(), which initialises the fixed data
* and enables the system log
*/
if (!application_init()) {
//LOG
return -1;
}
// Create Main task to
if (oceos_task_create(t_0,// taskID, used as index, must be in range 0 to 254
10, // priority, must be in range 1 to 254, lower value is higher priority
10, // threshold, must be in range 1 to task priority
1, // jobs_max, must be in range 1 to 15
0,// FALSE -> floating point hardware not used by task
1, // FALSE -> task initially not enabled
fun0, // main body of task
nullFun, // task end function
0,// time_deadline, must finish no later than this after start, 0 => ignore
0 // minimum time expected between start requests, 0 => no restriction
) != SUCCESSFUL)
return 1;
if (oceos_task_create(t_1, 100, 100, 1, 0, 1, fun1, nullFun, 0, 0)
!= SUCCESSFUL)
return 2;
if (oceos_task_create(t_2, 100, 100, 1, 0, 1, fun2, nullFun, 0, 0)
!= SUCCESSFUL)
return 3;
if (oceos_sem_create(items, 10, 0, 2, FALSE) != SUCCESSFUL)// items semaphore with max permits of 10, initial permits of 0, max jobs 2
return 4;
if (oceos_sem_create(spaces, 10, 4, 2, FALSE) != SUCCESSFUL) // spaces semaphore with max permits of 10, initial permits of 4, max jobs 2
return 4;
/*
* Finish initialising OCEOS and setting up the fixed data
*/
status = oceos_init_finish();
if (SUCCESSFUL != status) {
return 6;
} // if
/*
* Start OCEOS scheduling
*
* The OCEOS fixed data provides all the information required.
*
* If a valid task is specified, it is started and passed the pointer.
* Otherwise the system is put in sleep mode
*/
status = oceos_start(fixed_data, t_0, (void*) nullPtr); // Start OCEOS with task to start other tasks
return status;
} // main
/*
* Application code functions, functions declared in asw.h
*/
void fun0(void *ptr) {
oceos_task_start(t_1, ptr); // Start consumer task
oceos_task_start(t_2, ptr); // Start consumer task
} // fun0()
void fun1(void *ptr) {
while (1) { // loop forever
if (oceos_sem_wait_restart(items) != SUCCESSFUL) {
printf("Error from task t_0 task waiting items\n");
}
printf("Got item\n");
if (oceos_sem_signal(spaces) != SUCCESSFUL) {
printf("Error from task t_0 signalling spaces\n");
}
}
} // fun0()
void fun2(void *ptr) {
while (1) { // loop forever
if (oceos_sem_wait_restart(spaces) != SUCCESSFUL) {
printf("Error from task t_1 task waiting spaces\n");
}
if (oceos_sem_signal(items) != SUCCESSFUL) {
printf("Error from task t_1 signalling items\n");
} else {
printf("Item done\n");
}
}
return;
} // fun1()
Tutorial 4 – Timer interrupt starts task
This exercise introduces the use of timer interrupts.
- Create one task
- Set a timer to interrupt every 2 seconds
- Set timer handler to start task
- Task outputs message, then exits
For code example see below:
tut4.h
/*
*********************************************************************************************************
* OCEOS
* Real-Time Operating System
* for
* ARM Microcontroller
*
* Example implementation of OCEOS
*
*
* (c) Copyright 2021, O.C.E. Technology
* All Rights Reserved
*
*
* Author: jfk
********************************************************************************************************
*/
#ifndef TUT4_H_
#define TUT4_H_
/* Sample Task names - all here start with t_ to help avoid name confusion */
enum TASK_NAME{
t_0, // Task to setup interrupt
t_1 // Task to be executed by interrupt routine
};
/*
* APPLICATION FUNCTION DECLARATIONS
*/
void fun0(void *);
void fun1(void *);
void start_task(void *arg, int source);
void timer_setup(void);
#endif /* TUT4_H_ */
oceos_config.h
/*
*********************************************************************************************************
* OCEOS
* Real-Time Operating System
* for
* ARM Microcontroller
*
* Example implementation of OCEOS
*
*
* (c) Copyright 2021, O.C.E. Technology
* All Rights Reserved
*
*
* Author: jfk
********************************************************************************************************
*/
#ifndef INCLUDE_OCEOS_CONFIG_H_
#define INCLUDE_OCEOS_CONFIG_H_
// 1: Includes OCEOS main header file
#include "oceos.h"
//----------------------------------------------------------------------------
// 2: Number of Log entries.
#define NUMBER_OF_LOG_ENTRIES 64 // 16 to 1024, default 64
//----------------------------------------------------------------------------
// 3: Number of tasks
#define NUMBER_OF_TASKS 2 // 1 to 255
//----------------------------------------------------------------------------
// 4: Number of ready queue entries, 0 to 254, see manual( MUST BE UPDATED BY USER);
// Defaults to number of tasks, as each task should have aa least one job;
// If Number of ready Q entries larger that number of total jobs => defaults to number of total jobs
#define NUMBER_OF_READYQ_ENTRIES NUMBER_OF_TASKS + 1
//----------------------------------------------------------------------------
// 5: Number of Mutexes
#define NUMBER_OF_MUTEXES 0 // 0 to 63
//----------------------------------------------------------------------------
// 6: Number of Semaphores
#define NUMBER_OF_SEMAPHORES 0 // 0 to 63
//----------------------------------------------------------------------------
// 7: Number of Data Qs
#define NUMBER_OF_DATAQS 0 // 0 to 63
//----------------------------------------------------------------------------
// 8: LOG data array size
#define LOG_DATA_ARRAY_SIZE_U32S 0x88// Calculated value. Read manual
//----------------------------------------------------------------------------
// 9: FIXED data array size
#define FIXED_DATA_ARRAY_SIZE_U32S 0x32// Calculated value. Read manual
//----------------------------------------------------------------------------
// 10: DYNAMIC data array size
#define DYN_DATA_ARRAY_SIZE_U32S 0x29// Calculated value. Read manual
//----------------------------------------------------------------------------
// 11: Timed Actions
#define NUMBER_OF_ACTION_ENTRIES 0 // User-modify field
//----------------------------------------------------------------------------
// 12: Log entries base 2
#define CS_LOG_DEF_ENTRIES_BASE2 0
//----------------------------------------------------------------------------
// 13: OCEOS stack start Address
#define OCEOS_STACK_START_ADDRESS 0
//----------------------------------------------------------------------------
// 14: OCEOS stack end address
#define OCEOS_STACK_LOW_BOUND_ADDRESS 0
//----------------------------------------------------------------------------
/**
* Target specific configurations
*/
/*
* ARM specific configurations
*/
#ifdef __SAM3X8E__
#ifndef BSP_SYSFREQ
#define BSP_SYSFREQ 84 // ARM target frequency in Mhz
#endif
#endif
#ifdef __SAMV71Q21__
#ifndef BSP_SYSFREQ
#define BSP_SYSFREQ 300 // ARM target frequency in Mhz
#endif
#endif
#ifdef __VA41620__
#ifndef BSP_SYSFREQ
#define BSP_SYSFREQ 100 // ARM target frequency in Mhz
#endif
#endif
//--------------------------------------------------------------------
// User defined function to deal with system errors
void oceos_on_error(void);
//---------------------------------------------------------------------
// User defined function to deal with log 2/3 full
void oceos_on_full_log(void);
//---------------------------------------------------------------------
extern U32_t log_data[];
extern U32_t fixed_data[];
extern U32_t dynamic_data[];
extern const unsigned int __oceos_bsp_sysfreq;
/**
* Initialize OCEOS with user configurations
*/
int application_init(void);
#endif /* INCLUDE_OCEOS_CONFIG_H_ */
oceos_config.c
/*
*********************************************************************************************************
* OCEOS
* Real-Time Operating System
* for
* ARM Microcontroller
*
* Example implementation of OCEOS
*
*
* (c) Copyright 2021, O.C.E. Technology
* All Rights Reserved
*
*
* Author: jfk
********************************************************************************************************
*/
#include <stdio.h>
#include "oceos_config.h"
/*
* OCEOS INTERNAL DATA STORAGE
*
* This application defines arrays to hold OCEOS internal data.
* The array sizes are provided by DMON by running "oceos info" command:</br>
* *Set all three arrays to guessed max zise, run application for the first time and exit.</br>
* *Run DMON command "oceos info" to get size for each array.</br>
* *Update array sizes below
*/
U32_t log_data[LOG_DATA_ARRAY_SIZE_U32S];
U32_t fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; // will be in data segment
U32_t dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];
const unsigned int __oceos_bsp_sysfreq = BSP_SYSFREQ * 1000 * 1000;// TODO
static BOOLE_t log_full_was_called = FALSE;
/**
* Must be defined if Application is using :
* Dataq with timeout
* Semaphore with timeout
* Timed Actions
*/
/*
* Set up the application configuration structure and pass it to oceos_init
* (done this way the memory used for the structure is returned automatically)
*/
int application_init(){
/*
* Create the application configuration structure
*/
struct application_configuration app_config = {0};
/*
* Fill in the application parameters
*/
app_config.log_address = (adrs_t)log_data; // required
app_config.fixed_data_address = (adrs_t)fixed_data; // required
app_config.dynamic_data_address = (adrs_t)dynamic_data; // required
app_config.stack_start_address = OCEOS_STACK_START_ADDRESS; // 0 => no check
app_config.stack_lower_bound_address = OCEOS_STACK_LOW_BOUND_ADDRESS; // 0 => no check
app_config.system_error_function = &oceos_on_error; // NULL => ignore
app_config.log_full_function = &oceos_on_full_log; // NULL => ignore
// used in setting up system log and fixed data array
app_config.log_number_of_entries = NUMBER_OF_LOG_ENTRIES; // 0 => use default
app_config.number_of_tasks = NUMBER_OF_TASKS; // >= 1
app_config.number_of_readyQ_entries = NUMBER_OF_READYQ_ENTRIES; // 0 => calculate size
app_config.number_of_mutexes = NUMBER_OF_MUTEXES;
app_config.number_of_counting_semaphores = NUMBER_OF_SEMAPHORES;
app_config.number_of_data_queues = NUMBER_OF_DATAQS;
app_config.timed_actions_queue_size = NUMBER_OF_ACTION_ENTRIES;
app_config.CS_log_entries_base2 = CS_LOG_DEF_ENTRIES_BASE2;
app_config.use_oceos_system_time = TRUE;
// initialise OCEOS
enum DIRECTIVE_STATUS status;
status = oceos_init(app_config);
if (SUCCESSFUL == status) {
return 1;
} else {
printf("\n oceos_init failure\n");
return -1;
} // else
} // application_init()
/**
* User to implement in case of system error;
* Comment it out if not used and set field system_error_function in app_config to NULL
*/
void oceos_on_error() {
return;
}
/**
* User to implement in case of system log is 2/3 full;
* Comment it out if not used and set field log_full_function in app_config to NULL
*/
void oceos_on_full_log(){
log_full_was_called = TRUE;
return;
}
arm_task_src.c
/*
*********************************************************************************************************
* OCEOS
* Real-Time Operating System
* for
* ARM Microcontroller
*
* Example implementation of OCEOS
*
*
* (c) Copyright 2021, O.C.E. Technology
* All Rights Reserved
*
*
* Author: jfk
********************************************************************************************************
*/
#include <stdio.h>
#include <stdlib.h>
#include "tut4.h"
#include "oceos_config.h"
#if defined(__SAM3X8E__) || defined(__SAMV71Q21__)
#include "sam.h"
#define ENABLE_WAVE_MODE (0x1 << TC_CMR_WAVE_Pos)
#define TC_CMR_WAVE_SEL_Pos 13
#define SET_WAVE_SELECT (~(0x3 << TC_CMR_WAVE_SEL_Pos)) //00
#define TC_CMR_CPCSTOP_Pos 6
#define TC_CMR_CPCSTOP (0x1 << TC_CMR_CPCSTOP_Pos)
static Tc *timer_regs;
static TcChannel *tc;
#endif
/*
* Set up timer and register handler
*/
void timer_setup(){
#ifdef __SAM3X8E__
// Enabling Peripheral Clocks
// REmove write protect
int pmc_was_enabled = 0;
if (0 != (PMC->PMC_WPMR & PMC_WPMR_WPEN)) {
PMC->PMC_WPMR = PMC_WPMR_WPKEY_PASSWD;
pmc_was_enabled = 1;
}
// Enable Clock
PMC->PMC_PCER0 |= PMC_PCER0_PID28;
// Enable write protect
if (pmc_was_enabled) {
PMC->PMC_WPMR = PMC_WPMR_WPKEY_PASSWD | PMC_WPMR_WPEN;
}
timer_regs = (Tc *)TC0;
tc = &(timer_regs->TC_CHANNEL[1]);
// Enable Wave Mode
tc->TC_CMR |= ENABLE_WAVE_MODE;
// Set WAVESEL to 00
tc->TC_CMR &= (U32_t)SET_WAVE_SELECT;
// Set TC_CMR_CPCSTOP and Clock input
tc->TC_CMR |= (TC_CMR_CPCSTOP | TC_CMR_TCCLKS_TIMER_CLOCK1); // MCK/8
// Set Block Clock
timer_regs->TC_BMR &= (U32_t)(~(1 << 1));
// Interrupt Enable
// Enable Timer interrupt (RC Compare)
tc->TC_IER = TC_IER_CPCS;
NVIC_EnableIRQ(TC1_IRQn);
// Set Highest Priority for interrupt number
NVIC_SetPriority(TC1_IRQn, 1);
float base_scaler = (float)(__oceos_bsp_sysfreq / 2) / 1000000.0f;
//tc->TC_RC = base_scaler * 0x3DC6C0;
tc->TC_RC = base_scaler * 1349;
// Enable clock
tc->TC_CCR = TC_CCR_CLKEN;
// Start clock
tc->TC_CCR = TC_CCR_SWTRG;
#endif
#ifdef __SAMV71Q21__
// Enabling Peripheral Clocks
// REmove write protect
int pmc_was_enabled = 0;
if (0 != (PMC->PMC_WPMR & PMC_WPMR_WPEN)) {
PMC->PMC_WPMR = PMC_WPMR_WPKEY_PASSWD;
pmc_was_enabled = 1;
}
// Enable Clock
PMC->PMC_PCER0 |= PMC_PCER0_PID24;
// Enable write protect
if (pmc_was_enabled) {
PMC->PMC_WPMR = PMC_WPMR_WPKEY_PASSWD | PMC_WPMR_WPEN;
}
timer_regs = (Tc *)TC0;
tc = &(timer_regs->TC_CHANNEL[1]);
// Enable Wave Mode
tc->TC_CMR |= ENABLE_WAVE_MODE;
// Set WAVESEL to 00
tc->TC_CMR &= (U32_t)SET_WAVE_SELECT;
// Set TC_CMR_CPCSTOP and Clock input
tc->TC_CMR |= (TC_CMR_CPCSTOP | TC_CMR_TCCLKS_TIMER_CLOCK5_Val); //
// Set Block Clock
timer_regs->TC_BMR &= (U32_t)(~(1 << 1));
// Interrupt Enable
// Enable Timer interrupt (RC Compare)
tc->TC_IER = TC_IER_CPCS;
NVIC_EnableIRQ(TC1_IRQn);
// Set Highest Priority for interrupt number
NVIC_SetPriority(TC1_IRQn, 1);
tc->TC_RC = 0x61a8;// 1s
// Enable clock
tc->TC_CCR = TC_CCR_CLKEN;
// Start clock
tc->TC_CCR = TC_CCR_SWTRG;
#endif
} // setup_timer()
void TC1_IRQHandler() {
#if defined(__SAM3X8E__) || defined(__SAMV71Q21__)
tc->TC_SR;// Read to remove pending bit
#endif
// Start task
oceos_task_start(t_1, NULL);
#if defined(__SAM3X8E__) || defined(__SAMV71Q21__)
tc->TC_CCR = TC_CCR_SWTRG;
#endif
}
tut4.c
/*
*********************************************************************************************************
* OCEOS
* Real-Time Operating System
* for
* ARM Microcontroller
*
* Example implementation of OCEOS
*
*
* (c) Copyright 2021, O.C.E. Technology
* All Rights Reserved
*
*
* Author: jfk
********************************************************************************************************
*/
#include <stdio.h>
#include <stdlib.h>
/* N.B. Application header is included first */
#include "oceos_config.h" // OCEOS header for this application
#include "tut4.h" // application header
volatile U32_t count_task_start = 0;
int main(void) {
int status;
/*
* Initialise the application configuration and OCEOS
*
* This application function creates the application configuration
* and passes it to oceos_init(), which initialises the fixed data
* and enables the system log
*/
if (!application_init()) {
//LOG
return -1;
}
// Create Main task to
if (oceos_task_create(t_0,// taskID, used as index, must be in range 0 to 254
10, // priority, must be in range 1 to 254, lower value is higher priority
10, // threshold, must be in range 1 to task priority
1, // jobs_max, must be in range 1 to 15
0,// FALSE -> floating point hardware not used by task
1, // FALSE -> task initially not enabled
fun0, // main body of task
NULL, // task end function
0,// time_deadline, must finish no later than this after start, 0 => ignore
0 // minimum time expected between start requests, 0 => no restriction
) != SUCCESSFUL)
return 1;
if (oceos_task_create(t_1, 100, 100, 1, 0, 1, fun1, NULL, 0, 0)
!= SUCCESSFUL)
return 2;
/*
* Finish initialising OCEOS and setting up the fixed data
*/
status = oceos_init_finish();
if (SUCCESSFUL != status) {
return 3;
} // if
/*
* Start OCEOS scheduling
*
* The OCEOS fixed data provides all the information required.
*
* If a valid task is specified, it is started and passed the pointer.
* Otherwise the system is put in sleep mode
*/
status = oceos_start(fixed_data, t_0, NULL); // Start OCEOS
return status;
} // main
/*
* Task 0 starting point
*/
void fun0(void *ptr) {
timer_setup();
} // fun0()
/**
* Task 1 starting point;
* Triggered from Timer IRQ handler
*/
void fun1(void *ptr) {
printf("Task started : %u times \n", count_task_start);
count_task_start++;
} // fun1()
Tutorial 5 – Using dataq with timed action
This exercise introduces the use of dataq with timed action.
- Create functions to be used by tasks
- Create one struct – pointer to these will be placed on queues
- Set timeout period T
- Create configuration structure with above configuration values for fields
- Initialize OCEOS using oceos_init()
- Create two tasks
- Create two data queues
For code example see below:
tut5.h
/*
******************************************************************************
* OCEOS
* Real-Time Operating System
* for ARM/SPARC
* Microcontroller
*
* Application Software Example Header File
*
*
* (c) Copyright 2021, O.C.E. Technology
* All Rights Reserved
*
* File : asw.h
* Author: Deniss Timofejevs <deniss.timofejevs@ocetechnology.com>
******************************************************************************
*/
#ifndef ASW_H
#define ASW_H
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "oceos_config.h" // OCEOS header
#include "oceos_timer.h"
#include "system_log.h"
#include "dataq.h"
#define N0 1 // dataq_size
#define N1 1 // dataq_size
#define JOBS0 1 // pending q size
#define JOBS1 1 // pending q size
#define TIME_OUT 1000000 // timeout
/*
* APPLICATION FUNCTION DECLARATIONS
*/
enum TASK_NAME{
t_consumer , // will have task ID 0
t_producer, // will have task ID 1
};
enum DATAQ_NAME{
queue_0, // will have dataq ID 0
queue_1, // will have dataq ID 1
};
void t_consumer_task(void);
void t_producer_task(void);
#endif /* ASW_H */
oceos_config.h
/*
* app_config.h
*
* Created on: 17 Feb 2020
* Author: Deniss Timofejevs <deniss.timofejevs@ocetechnology.com>
*/
#ifndef INCLUDE_OCEOS_CONFIG_H_
#define INCLUDE_OCEOS_CONFIG_H_
// 1: Includes OCEOS main header file
#include "oceos.h"
//----------------------------------------------------------------------------
// 2: Number of Log entries.
#define NUMBER_OF_LOG_ENTRIES 16 // 16 to 1024, default 64
//----------------------------------------------------------------------------
// 3: Number of tasks
#define NUMBER_OF_TASKS 2 // 1 to 255
//----------------------------------------------------------------------------
// 4: Number of ready queue entries, 0 to 254, see manual( MUST BE UPDATED BY USER);
// Defaults to number of tasks, as each task should have aa least one job;
// If Number of ready Q entries larger that number of total jobs => defaults to number of total jobs
#define NUMBER_OF_READYQ_ENTRIES 3
//----------------------------------------------------------------------------
// 5: Number of Mutexes
#define NUMBER_OF_MUTEXES 0 // 0 to 63
//----------------------------------------------------------------------------
// 6: Number of Semaphores
#define NUMBER_OF_SEMAPHORES 0 // 0 to 63
//----------------------------------------------------------------------------
// 7: Number of Data Qs
#define NUMBER_OF_DATAQS 2 // 0 to 63
//----------------------------------------------------------------------------
// 8: LOG data array size
#define LOG_DATA_ARRAY_SIZE_U32S 0x28// Calculated value. Read manual
//----------------------------------------------------------------------------
// 9: FIXED data array size
#define FIXED_DATA_ARRAY_SIZE_U32S 0x34// Calculated value. Read manual
//----------------------------------------------------------------------------
// 10: DYNAMIC data array size
#define DYN_DATA_ARRAY_SIZE_U32S 0x46// Calculated value. Read manual
//----------------------------------------------------------------------------
// 11: Timed Actions
#define NUMBER_OF_ACTION_ENTRIES 0 // User-modify field
//----------------------------------------------------------------------------
// 12: Log entries base 2
#define CS_LOG_DEF_ENTRIES_BASE2 0
//----------------------------------------------------------------------------
// 13: OCEOS stack start Address
#define OCEOS_STACK_START_ADDRESS 0
//----------------------------------------------------------------------------
// 14: OCEOS stack end address
#define OCEOS_STACK_LOW_BOUND_ADDRESS 0
//----------------------------------------------------------------------------
/**
* Target specific configurations
*/
#ifdef __SAM3X8E__
#ifndef BSP_SYSFREQ
#define BSP_SYSFREQ 84 // ARM target frequency in Mhz
#endif
#endif
#ifdef __SAMV71Q21__
#ifndef BSP_SYSFREQ
#define BSP_SYSFREQ 300 // ARM target frequency in Mhz
#endif
#endif
#ifdef __VA41620__
#ifndef BSP_SYSFREQ
#define BSP_SYSFREQ 100 // ARM target frequency in Mhz
#endif
#endif
// User defined function to deal with system errors
void oceos_on_error(void*);
//---------------------------------------------------------------------
// User defined function to deal with log 2/3 full
void oceos_on_full_log(void*);
//---------------------------------------------------------------------
extern U32_t log_data[];
extern U32_t fixed_data[];
extern U32_t dynamic_data[];
extern const unsigned int __oceos_bsp_sysfreq;
/**
* Initialize OCEOS with user configurations
*/
int application_init(void);
#endif /* INCLUDE_OCEOS_CONFIG_H_ */
oceos_config.c
/*
* app_config.c
*
* Configuration Tamplate for OCEOS
*
* Created on: 17 Feb 2020
* Author: Deniss Timofejevs <deniss.timofejevs@ocetechnology.com>
*/
#include <stdio.h>
#include <assert.h>
#include "oceos_config.h"
/*
* OCEOS INTERNAL DATA STORAGE
*
* This application defines arrays to hold OCEOS internal data.
* The array sizes are provided by DMON by running "oceos info" command:</br>
* *Set all three arrays to guessed max zise, run application for the first time and exit.</br>
* *Run DMON command "oceos info" to get size for each array.</br>
* *Update array sizes below
*/
U32_t log_data[LOG_DATA_ARRAY_SIZE_U32S];
U32_t fixed_data[FIXED_DATA_ARRAY_SIZE_U32S] = {0}; // will be in data segment
U32_t dynamic_data[DYN_DATA_ARRAY_SIZE_U32S];
const unsigned int __oceos_bsp_sysfreq = BSP_SYSFREQ * 1000 * 1000;// TODO
static BOOLE_t log_full_was_called = FALSE;
/*
* Set up the application configuration structure and pass it to oceos_init
* (done this way the memory used for the structure is returned automatically)
*/
int application_init(){
/*
* Create the application configuration structure
*/
struct application_configuration app_config = {0};
/*
* Fill in the application parameters
*/
app_config.log_address = (adrs_t)log_data; // required
app_config.fixed_data_address = (adrs_t)fixed_data; // required
app_config.dynamic_data_address = (adrs_t)dynamic_data; // required
app_config.stack_start_address = OCEOS_STACK_START_ADDRESS; // 0 => no check
app_config.stack_lower_bound_address = OCEOS_STACK_LOW_BOUND_ADDRESS; // 0 => no check
app_config.system_error_function = &oceos_on_error; // NULL => ignore
app_config.log_full_function = &oceos_on_full_log; // NULL => ignore
// used in setting up system log and fixed data array
app_config.log_number_of_entries = NUMBER_OF_LOG_ENTRIES; // 0 => use default
app_config.number_of_tasks = NUMBER_OF_TASKS; // >= 1
app_config.number_of_readyQ_entries = NUMBER_OF_READYQ_ENTRIES; // 0 => calculate size
app_config.number_of_mutexes = NUMBER_OF_MUTEXES;
app_config.number_of_counting_semaphores = NUMBER_OF_SEMAPHORES;
app_config.number_of_data_queues = NUMBER_OF_DATAQS;
app_config.timed_actions_queue_size = NUMBER_OF_ACTION_ENTRIES;
app_config.CS_log_entries_base2 = CS_LOG_DEF_ENTRIES_BASE2;
app_config.use_oceos_system_time = TRUE;
// initialise OCEOS
enum DIRECTIVE_STATUS status;
status = oceos_init(app_config);
assert(SUCCESSFUL == status);
if (SUCCESSFUL == status) {
return 1;
} else {
printf("\n oceos_init failure\n");
return -1;
} // else
} // application_init()
/**
* User to implement in case of system error;
* Comment it out if not used and set field system_error_function in app_config to NULL
*/
void oceos_on_error(void* ptr) {
return;
}
/**
* User to implement in case of system log is 2/3 full;
* Comment it out if not used and set field log_full_function in app_config to NULL
*/
void oceos_on_full_log(void* ptr){
log_full_was_called = TRUE;
return;
}
tut5.c
/*
******************************************************************************
* OCEOS
* Real-Time Operating System
* for ARM/SPARC
* Microcontroller
*
* Application Software Example
*
*
* (c) Copyright 2022, O.C.E. Technology
* All Rights Reserved
*
* Author: jfk
*
* Purpose : The test here involves creating two tasks with different priorities,
* and two data queues with timed action implimentation.
*
******************************************************************************
*/
/* N.B. Application header is included first */
#include "tut5.h" // application header
struct data {
int status;
char *message;
} test_data = {
1,
"Test Data",
};
int main(void) {
/*
* Initialise the application configuration and OCEOS
*
* This application function creates the application configuration
* and passes it to oceos_init(), which initialises the fixed data
* and enables the system log
*/
if ( !application_init()) {
//LOG
printf("\nProblem\n");
return -1;
}
enum DIRECTIVE_STATUS status;
// Task 0: priority 10, threshold 10, max jobs 1, FP_used disabled, initially_enabled TRUE, task start address t_consumer_task, start of task end function NULL, time_deadline 0, time_mininterstart 0
status = oceos_task_create(t_consumer, 10, 10, 1, 0, TASK_ENABLED,t_consumer_task, NULL, 0, 0);
if(SUCCESSFUL != status){
// LOG
printf("\nAbandoning, problem creating task t_consumer, resulting return code: %u\n", status);
return -1;
} // if
// Task 1: priority 254, threshold 254, max jobs 1, FP_used disabled, initially_enabled TRUE, task start address t_consumer_task, start of task end function NULL, time_deadline 0, time_mininterstart 0
status = oceos_task_create(t_producer, 254, 254, 1, 0, TASK_ENABLED,t_producer_task, NULL, 0, 0);
if(SUCCESSFUL != status){
// LOG
printf("\nAbandoning, problem creating task t_producer, resulting return code: %u\n", status);
return -1;
} // if
printf("\n Tasks created\n");
// no counting semaphores, data queues or user defined traps
// Creating Data 0, dataq_size 1, pen_q size 1, roll_over FALSE, use_timeout TRUE
status = oceos_dataq_create(queue_0, N0, JOBS0, FALSE, TRUE);
if(SUCCESSFUL != status){
printf("\nProblem creating dataq queue_0, resulting return code: %u\n", status);
} // if
// Creating Data 1, dataq_size 1, pen_q size 1, roll_over FALSE, use_timeout TRUE
status = oceos_dataq_create(queue_1, N1, JOBS1, FALSE, TRUE);
if(SUCCESSFUL != status){
printf("\nProblem creating dataq queue_1, resulting return code: %u\n", status);
} // if
/*
* Finish initialising OCEOS and setting up the fixed data
*/
status = oceos_init_finish();
if(SUCCESSFUL != status){
printf("\nAbandoning, problem ending OCEOS initialisation, resulting return code: %u\n", status);
return -1;
} // if
//1) Action: Start OCEOS with Task 1 as initial task, null input pointer
status = oceos_start(fixed_data, t_producer, NULL);
return status; // returned as an integer
} // function waits for specific time interval
void test_wait(U32_t interval) {
volatile U32_t start_time = oceos_time_sys_get32();
volatile U32_t cur_time = 0;
while(1) {
cur_time = oceos_time_sys_get32();
if ((cur_time - start_time) >= interval ) {
break;
}
}
}
/*
* Tasks
*/
void t_consumer_task() {
static int case_number = 0;
if (case_number == 0) {
case_number++;
// 2) Action: Task 1 attempts to start Task 0
// Check: Task 0 has started, pre-empting Task 1
// a. Check: entry message from Task 0
// b. Check: queue_0 entries is 0
// c. Check: queue_1 entries is 0
printf("t_consumer was started\n");
if(oceos_dataq_get_size(queue_0)!= 0){
printf("\nData queue_0 entries is not equal to 0\n");
} // if
if(oceos_dataq_get_size(queue_1)!= 0){
printf("\nData queue_1 entries is not equal to 0\n");
} // if
// 3) Action: Task 0 does read_restart on queue_0
oceos_dataq_read_restart_timeout(queue_0, 0);
} else if (case_number == 1){
case_number++;
// 5) Action: Task 1 writes pointer to struct to queue_0
// Check: Task 0 has started, pre-empting Task 1
// a. Check: entry message from Task 0
// b. Check: queue_0 entries count is 1
// c. Check: queue_1 entries count is 0
printf("t_consumer was started\n");
if(oceos_dataq_get_size(queue_0)!= 1){
printf("\nData queue_0 entries is not equal to 1\n");
} // if
if(oceos_dataq_get_size(queue_1)!= 0){
printf("\nData queue_1 entries is not equal to 0\n");
} // if
// 6) Action: Task 0 does read_restart on queue 0
// Check: Task 0 has succeeded
// a. Check: non-null pointer returned
// b. Check: queue_0 entries count is 0
// c. Check: queue_0 entries count is 0
if(oceos_dataq_read_restart_timeout(queue_0, 0) == NULL){
printf("\nDataq read restart timeout returned null\n");
} // if
if(oceos_dataq_get_size(queue_0)!= 0){
printf("\nData queue_0 entries is not equal to 0\n");
} // if
if(oceos_dataq_get_size(queue_1)!= 0){
printf("\nData queue_1 entries is not equal to 0\n");
} // if
// 7) Action: Task 0 writes this pointer to queue_1
// Check: Task 0 has succeeded
// a. Check: queue_0 entries count is 0
// b. Check: queue_1 entries count is 1
if(oceos_dataq_write(queue_1, &test_data) != SUCCESSFUL){
printf("\nDataq write was not succesful\n");
} // if
if(oceos_dataq_get_size(queue_0)!= 0){
printf("\nData queue_0 entries is not equal to 0\n");
} // if
if(oceos_dataq_get_size(queue_1)!= 1){
printf("\nData queue_1 entries is not equal to 1\n");
} // if
// 8) Action: Task 0 does read_restart with timeout on queue_0
// Check: Task 0 exits as queues_0 is empty
if(oceos_dataq_read_restart_timeout(queue_0, TIME_OUT) != NULL){
printf("\nDataq read restart timeout returned not null\n");
} // if
} else {
case_number++;
// 10) Action: Task 1 loops for at least twice timeout period T
// Check: Task 0 restarts on timeout, pre-empting Task 1
// a. Check: entry message from Task 0
// b. Check: queue_0 entries count is 0
// c. Check: queue_1 entries count is 0
printf("t_consumer was started\n");
if(oceos_dataq_get_size(queue_0)!= 0){
printf("\nData queue_0 entries is not equal to 0\n");
} // if
if(oceos_dataq_get_size(queue_1)!= 0){
printf("\nData queue_1 entries is not equal to 0\n");
} // if
// 11) Action: Task 0 does read_continue on queue_0
// Check: Task 0 has succeeded
// a. Check: null pointer returned
// b. Check: queue_0 entries count is 0
// c. Check: queue_1 entries count is 0
if(oceos_dataq_read_continue(queue_0) != NULL){
printf("\nDataq read continue returned not null\n");
} // if
if(oceos_dataq_get_size(queue_0)!= 0){
printf("\nData queue_0 entries is not equal to 0\n");
} // if
if(oceos_dataq_get_size(queue_1)!= 0){
printf("\nData queue_1 entries is not equal to 0\n");
} // if
// 12) Action: Task 0 exits
// Check: Task 0 exit message
// a. Check: queue_0 entries count is 0
// b. Check: queue_1 entries count is 0
printf("t_consumer is exiting\n");
if(oceos_dataq_get_size(queue_0)!= 0){
printf("\nData queue_0 entries is not equal to 0\n");
} // if
if(oceos_dataq_get_size(queue_1)!= 0){
printf("\nData queue_1 entries is not equal to 0\n");
} // if
return;
}
}//END t_consumer_task
void t_producer_task() {
// 1) Action: Start OCEOS with Task 1 as initial task, null input pointer
// Check: Task 1 has started
// a. Check: Starting message from Task 1
// b. Check: queue_0 entries count is 0
// c. Check: queue_0 capacity is as created
// d. Check: queue_1 entries count is 0
// e. Check: queue_1 capacity is as created
printf("t_producer was started\n");
if(oceos_dataq_get_size(queue_0)!= 0){
printf("\nData queue_0 entries is not equal to 0\n");
} // if
if(oceos_dataq_get_size(queue_1)!= 0){
printf("\nData queue_1 entries is not equal to 0\n");
} // if
// 2) Action: Task 1 attempts to start Task 0
if(oceos_task_start(t_consumer, NULL)!= SUCCESSFUL){
printf("\nFailed starting task t_consumer\n");
} // if
// 3) Action: Task 0 does read_restart on queue_0
// Check: Task 0 exits as queue_0 is empty
// Check: Task 1 continues
// a. Check: continue message from Task 1
// b. Check: queue_0 entries count is 0
// c. Check: queue_1 entries count is 0
printf("t_producer continues \n");
if(oceos_dataq_get_size(queue_0)!= 0){
printf("\nData queue_0 entries is not equal to 0\n");
} // if
if(oceos_dataq_get_size(queue_1)!= 0){
printf("\nData queue_1 entries is not equal to 0\n");
} // if
// 4) Action: Task 1 does read_continue on queue_1
// Check: null pointer returned
if(oceos_dataq_read_continue(queue_1) != NULL){
printf("\nDataq read continue returned not null\n");
} // if
// 5) Action: Task 1 writes pointer to struct to queue_0
if(oceos_dataq_write(queue_0, &test_data) != SUCCESSFUL){
printf("\nDataq write failed\n");
} // if
// 8) Action: Task 0 does read_restart with timeout on queue_0
// Check: Task 0 exits as queues_0 is empty
// Check: Task 1 continues
// a. Check: continue message from Task 1
// b. Check: queue_0 entries count is 0
// c. Check: queue_1 entries count is 1
printf("t_producer continues \n");
if(oceos_dataq_get_size(queue_0)!= 0){
printf("\nData queue_0 entries is not equal to 0\n");
} // if
if(oceos_dataq_get_size(queue_1)!= 1){
printf("\nData queue_1 entries is not equal to 1\n");
} // if
// 9) Action: Task 1 does read_continue on queue_1
// Check: Non-null pointer returned
// a. Check: pointer to same struct
// b. Check: queue_0 entries count is 0
// c. Check: queue_1 entries count is 0
struct data *temp_data = oceos_dataq_read_continue(queue_1);
if(temp_data == NULL){
printf("\ntemp_data is null\n");
} // if
if(test_data.message != temp_data->message){
printf("\npointer not to same struct\n");
} // if
if(oceos_dataq_get_size(queue_0)!= 0){
printf("\nData queue_0 entries is not equal to 0\n");
} // if
if(oceos_dataq_get_size(queue_1)!= 0){
printf("\nData queue_1 entries is not equal to 0\n");
} // if
// 10) Action: Task 1 loops for at least three timeout period
// Check: Task 0 restarts on timeout, pre-empting Task 1
test_wait(TIME_OUT * 3);
//Task 1 writes pointer to struct on queue_1
if(oceos_dataq_write(queue_1, &test_data) != SUCCESSFUL){
printf("\nDataq write failed\n");
} // if
// Data q size check
if(oceos_dataq_get_size(queue_1)!= 1){
printf("\nData queue_1 entries is not equal to 1\n");
} // if
// Task 1 does read restart on queue_1
if(oceos_dataq_read_restart(queue_1) == NULL){
printf("\nDataq read restart failed\n");
} // if
// Data q size check
if(oceos_dataq_get_size(queue_1)!= 0){
printf("\nData queue_1 entries is not equal to 0\n");
} // if
//Task 1 writes pointer to struct on queue_1
if(oceos_dataq_write(queue_1, &test_data) != SUCCESSFUL){
printf("\nDataq write failed\n");
} // if
// Data q size check
if(oceos_dataq_get_size(queue_1)!= 1){
printf("\nData queue_1 entries is not equal to 1\n");
} // if
// Data q clear
if(oceos_dataq_clear(queue_1)!= 0){
printf("\nDataq clear failed\n");
} // if
// Data q size check
if(oceos_dataq_get_size(queue_1)!= 0){
printf("\nData queue_1 entries is not equal to 0\n");
} // if
// Data pending q size check
if(oceos_dataq_penq_get_size(queue_1) != 0){
printf("\nDataq pending queue not equal to 0\n");
} // if
// 14) Action: Task 1 terminates
// Check: Task 1 exit message
printf("t_producer is exiting\n");
// 15) Action: CPU placed in sleep mode
// Check: Sleep mode starting message
if(oceos_exit() != SUCCESSFUL){
printf("\nOceos exiting failed\n");
} // if
return;
}